Compare commits

..

170 Commits

Author SHA1 Message Date
8d85ad5269 Merge pull request 'master' (#1) from wagshome/buildx:master into master
Reviewed-on: https://gitea.wagshome.duckdns.org/publicWagsHome/buildx/pulls/1
2023-10-29 19:36:47 +00:00
nathan wagner
008ce88567 messing this up 2023-09-11 10:36:54 -04:00
nathan wagner
17a7e99226 Revert "both driver-opt and security-opt options"
This reverts commit a12bc79097.
2023-09-11 10:09:38 -04:00
nathan wagner
027a8c16e7 adding in updates 2023-09-11 09:57:24 -04:00
a12bc79097 both driver-opt and security-opt options 2023-09-11 00:56:14 +00:00
a0b5a420e8 security options 2023-09-10 05:31:03 +00:00
nathan wagner
0151ea9a3f maskedPath 2023-09-07 19:46:23 +00:00
nathan wagner
221d091b68 removing debugging 2023-09-07 13:08:41 +00:00
1760b8b586 doing it 2023-09-07 12:58:45 +00:00
nathan wagner
4d142d8b45 doing it 2023-09-06 20:20:46 +00:00
nathan wagner
44dd1f1f5e i want buildx binary to be static on out 2023-09-05 20:26:26 +00:00
CrazyMax
f35b2b7cab Merge pull request #2032 from docker/dependabot/github_actions/actions/checkout-4
build(deps): bump actions/checkout from 3 to 4
2023-09-05 08:36:03 +02:00
dependabot[bot]
29ba5ecef6 build(deps): bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 18:51:00 +00:00
Justin Chadwell
87e8e4b847 Merge pull request #2029 from testwill/loop
chore: slice loop replace
2023-08-31 07:10:10 +02:00
guoguangwu
a71a24c0f4 chore: slice loop replace
Signed-off-by: guoguangwu <guoguangwu@magic-shield.com>
2023-08-31 12:24:02 +08:00
Tõnis Tiigi
76119b0f61 Merge pull request #2026 from ktock/fix-invoke-flag
debug: fix short-form custom command name on `--invoke` isn't used
2023-08-30 10:05:49 -07:00
Kohei Tokunaga
7843b5f417 debug: fix short-form custom command name on --invoke isn't used
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
2023-08-30 18:41:16 +09:00
Justin Chadwell
da6662975f Merge pull request #2019 from jedevc/chore-bake-field-reorder 2023-08-24 14:17:55 +01:00
Justin Chadwell
de4dbb7d00 chore: reorder target fields
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-08-24 14:01:14 +01:00
Justin Chadwell
3bd4bca994 Merge pull request #2013 from jedevc/tests-add-imagetools-create
tests: add imagetools tests for copying manifests and indexes
2023-08-23 13:31:45 +01:00
CrazyMax
296832c90e Merge pull request #2014 from crazy-max/fix-compose-test
test: fix non-deterministic compose context path
2023-08-23 11:27:47 +02:00
CrazyMax
56d55a4137 test: fix non-deterministic compose context path
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-08-23 11:15:50 +02:00
CrazyMax
626e6f8fa3 Merge pull request #1905 from thaJeztah/cgroup_parent_description
update flag-description for --cgroup-parent
2023-08-23 10:15:47 +02:00
Justin Chadwell
5941bf0494 tests: add imagetools tests for copying manifests and indexes
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-08-22 17:38:36 +01:00
CrazyMax
29a496cdab Merge pull request #2012 from jedevc/git-propogate-errors
git: propogate failure to locate git binary
2023-08-22 13:30:36 +02:00
Justin Chadwell
a43d9a67c7 git: fix error wrapping to ensure internal errors are propogated
Also, tidy up the error printing, so that now we always print out the
"current commit information was not captured by the build" message,
instead of just for not locating the git binary.

Before:

	WARNING: buildx: git was not found in the system. Current commit information was not captured by the build

After:

	WARNING: current commit information was not captured by the build: git was not found in the system: <error message>

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-08-22 12:17:17 +01:00
Justin Chadwell
c47eb3bf5a git: propogate failure to locate git binary
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-08-22 12:16:19 +01:00
CrazyMax
a97e1641a4 Merge pull request #2000 from jedevc/fix-race-container-creation
docker-container: avoid fail if container conflict
2023-08-21 16:11:02 +02:00
Akihiro Suda
86ae8ea854 Merge pull request #1999 from crazy-max/update-k8s
vendor: bump k8s to v0.26.7
2023-08-10 23:26:24 +09:00
Justin Chadwell
d37d483097 docker-container: avoid fail if container conflict
Fixes the race condition where two boots are executed simultaneously
across multiple processes.

We initially check to see if the container exists, but if during
container creation we get a name conflict, we don't treat this error as
a hard failure, and instead move immediately into waiting for the node
to boot.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-08-10 14:29:36 +01:00
CrazyMax
4e96faa201 vendor: bump k8s to v0.26.7
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-08-10 15:22:24 +02:00
Tõnis Tiigi
e5419ef6d7 Merge pull request #1927 from crazy-max/fix-load-status
build: read body response to check for erroneous image export to docker
2023-08-10 12:29:03 +03:00
CrazyMax
14747a490a Merge pull request #1971 from glours/bump-compose-go-v1.17.0
bump compose-go version to v1.17.0 to fix issue with depends_on
2023-08-08 21:03:59 +02:00
Justin Chadwell
e5cee892ed Merge pull request #1965 from mqasimsarfraz/qasim/oci-annotations 2023-08-08 14:36:26 +01:00
CrazyMax
ef4b984df4 build: read body response to check for erroneous image export to docker
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-08-08 06:34:24 +02:00
CrazyMax
a8f402e28d Merge pull request #1993 from kenyon/typo-fix
README: fix typo
2023-08-08 06:32:44 +02:00
Kenyon Ralph
2eba99b40b README: fix whitespace
Signed-off-by: Kenyon Ralph <quic_kralph@quicinc.com>
2023-08-07 11:34:13 -07:00
Kenyon Ralph
7686fa1f16 README: fix typo
Signed-off-by: Kenyon Ralph <quic_kralph@quicinc.com>
2023-08-07 11:33:54 -07:00
Justin Chadwell
51b9bab245 Merge pull request #1987 from jedevc/vendor-buildkit-master-tests 2023-08-07 17:08:16 +01:00
CrazyMax
6b5758f4cd Merge pull request #1821 from jedevc/allow-debug-env
commands: consume DEBUG environment variable
2023-08-07 15:06:47 +02:00
CrazyMax
bd375a14a8 Merge pull request #1940 from kenyon/patch-1
README: clarify the Linux package install instructions
2023-08-07 14:43:29 +02:00
CrazyMax
b01693f63e bake: test compose include
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-08-04 17:24:30 +02:00
Guillaume Lours
4a059d5144 adapt compose unit tests, build context is now transformed to absolute paths by compose-go
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2023-08-04 17:23:12 +02:00
Guillaume Lours
f3775c0046 bump compose-go version to v1.17.0 to fix issue with depends_on
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2023-08-04 17:23:04 +02:00
Justin Chadwell
50fbdd86f9 Merge pull request #1985 from jsternberg/integration-test/version 2023-08-04 16:14:42 +01:00
Justin Chadwell
1f61de0fcc Merge pull request #1988 from jedevc/fix-attests-on-docker-driver 2023-08-04 16:07:21 +01:00
Justin Chadwell
e206c585bb build: error on attests on non-multiplatform driver
On drivers that do not support multi-platform builds (the default
`docker` driver), we do not support building attestations (unless using
the containerd store).

We need to check this feature before attempting to build using
attestations.

Also adds a test to ensure that attestations can be pushed to registries
at all, and that it adequately fails on the docker driver.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-08-04 15:28:32 +01:00
Justin Chadwell
5e46d8057d tests: add unsupported features detection skeleton
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-08-04 12:00:18 +01:00
Justin Chadwell
4e7709e54c vendor: update buildkit to master@b49a8873179b
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-08-04 12:00:18 +01:00
Justin Chadwell
5ed8f1b7d9 tests: avoid hardcoded driver check in testImageIDOutput
To detect if there is a docker daemon available, we can use the sandbox
.DockerAddress() function.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-08-04 11:22:10 +01:00
Jonathan A. Sternberg
1d12c1f5b3 Integration test for docker buildx version
An integration test for `docker buildx version` has been created. The
integration test checks that there is one line output, the output is
composed of three sections, and that these sections could feasibly be
the package path, version, and revision information.

The intention of the checks is to find obvious errors in the output like
the package path not existing or the version and revision being swapped.
It is not intended to assert that these values must be certain values
because it is assumed these values may vary depending on the build
process for buildx.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2023-08-03 09:51:03 -05:00
Qasim Sarfraz
3ef93e081c tests: add testImagetoolsAnnotation integration test
Signed-off-by: Qasim Sarfraz <qasimsarfraz@microsoft.com>
2023-08-03 12:16:40 +02:00
Qasim Sarfraz
18894a8e3a allow annotations for OCI image index
Signed-off-by: Qasim Sarfraz <qasimsarfraz@microsoft.com>
2023-08-03 12:08:04 +02:00
Justin Chadwell
13ec635988 Merge pull request #1914 from ktock/updatedebugdocs 2023-08-03 09:52:13 +01:00
Tõnis Tiigi
f804b8fa4b Merge pull request #1982 from thaJeztah/update_go1.20.7
update to go1.20.7
2023-08-03 10:59:18 +03:00
Kenyon Ralph
21a55ff9a1 README: clarify the Linux package install instructions
Signed-off-by: Kenyon Ralph <quic_kralph@quicinc.com>
2023-08-02 13:55:22 -07:00
Sebastiaan van Stijn
dd350284df update to go1.20.7
Includes a fix for CVE-2023-29409

go1.20.7 (released 2023-08-01) includes a security fix to the crypto/tls
package, as well as bug fixes to the assembler and the compiler. See the
Go 1.20.7 milestone on our issue tracker for details:

- https://github.com/golang/go/issues?q=milestone%3AGo1.20.7+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.20.6...go1.20.7

From the mailing list announcement:

[security] Go 1.20.7 and Go 1.19.12 are released

Hello gophers,

We have just released Go versions 1.20.7 and 1.19.12, minor point releases.

These minor releases include 1 security fixes following the security policy:

- crypto/tls: restrict RSA keys in certificates to <= 8192 bits

  Extremely large RSA keys in certificate chains can cause a client/server
  to expend significant CPU time verifying signatures. Limit this by
  restricting the size of RSA keys transmitted during handshakes to <=
  8192 bits.

  Based on a survey of publicly trusted RSA keys, there are currently only
  three certificates in circulation with keys larger than this, and all
  three appear to be test certificates that are not actively deployed. It
  is possible there are larger keys in use in private PKIs, but we target
  the web PKI, so causing breakage here in the interests of increasing the
  default safety of users of crypto/tls seems reasonable.

  Thanks to Mateusz Poliwczak for reporting this issue.

View the release notes for more information:
https://go.dev/doc/devel/release#go1.20.7

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-08-02 00:06:05 +02:00
Tõnis Tiigi
c010d3de8d Merge pull request #1967 from thaJeztah/update_cli
vendor: github.com/docker/docker, github.com/docker/cli v24.0.5
2023-08-01 11:51:44 +03:00
Justin Chadwell
d11dbbf9f7 Merge pull request #1978 from tonistiigi/imagetools-test 2023-07-31 15:39:42 +01:00
Tonis Tiigi
75cdceb9f1 tests: add integration test for imagetools create
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2023-07-31 17:17:11 +03:00
Tõnis Tiigi
10ff93f190 Merge pull request #1968 from jedevc/reset-dont-modify-input
progress: don't modify ResetTime inputs
2023-07-31 16:02:23 +03:00
CrazyMax
bf00185809 Merge pull request #1681 from crazy-max/fup-buildinfo
docs: update since buildinfo removal
2023-07-31 10:55:30 +02:00
CrazyMax
90f03e57c2 Merge pull request #1972 from crazy-max/docs-fix-create
docs: fix platform example for create command
2023-07-31 10:54:26 +02:00
Justin Chadwell
a59fd3ebfe Merge pull request #1970 from ktock/entrypointconfig 2023-07-27 15:21:37 +01:00
Kohei Tokunaga
3eb490153d remote controller: Fix entrypoint interaction bugs
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
2023-07-27 09:12:52 +09:00
CrazyMax
d957d8b987 docs: fix platform example for create command
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-07-26 17:50:58 +02:00
Justin Chadwell
5a1f252bd9 progress: don't modify ResetTime inputs
No other parts of the progress rendering modify the inputs, so we should
avoid this as well.

This actually fixes an edge case in pushWithMoby which writes the same
VertexStatus multiple times, modifying the timestamps and similar.
However, if the operation takes long enough the small time difference
can accumulate, and move the Start time far into the past.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-07-25 09:35:43 +01:00
Sebastiaan van Stijn
ab4585f38c vendor: github.com/docker/cli v24.0.5
Fix a panic when `auths: null` is found in the CLI config file.

full diff: https://github.com/docker/cli/compare/v24.0.4...v24.0.5

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-25 09:09:50 +02:00
Sebastiaan van Stijn
3003045c0b vendor: github.com/docker/docker v24.0.5
- client: Client.postHijacked: use Client.buildRequest

full diff: https://github.com/moby/moby/compare/36e9e796c6fc...v24.0.5

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-25 09:09:02 +02:00
Sebastiaan van Stijn
a6f3f290b4 vendor: golang.org/x/net v0.10.0
- http2: properly discard data received after request/response body is closed
- http2: don't reuse connections that are experiencing errors
- internal/socks: permit authenticating with an empty password

full diff: https://github.com/golang/net/compare/v0.8.0...v0.10.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-25 09:05:20 +02:00
Sebastiaan van Stijn
27d072a099 vendor: golang.org/x/text v0.9.0
no changes in vendored files

full diff: https://github.com/golang/text/compare/v0.8.0...v0.9.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-25 09:04:17 +02:00
Sebastiaan van Stijn
8e3df1943c vendor: golang.org/x/term v0.8.0
no changes in vendored files

full diff: https://github.com/golang/term/compare/v0.6.0...v0.8.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-25 09:03:14 +02:00
Sebastiaan van Stijn
8c54de66ce vendor: golang.org/x/sys v0.8.0
full diff: https://github.com/golang/sys/compare/v0.7.0...v0.8.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-25 09:02:03 +02:00
Sebastiaan van Stijn
06b9ac2dc4 vendor: github.com/sirupsen/logrus v1.9.3
Fix a potential denial of service in logrus.Writer() that could be triggered
by logging text longer than 64kb without newlines.

full diff: https://github.com/sirupsen/logrus/compare/v1.9.0...v1.9.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-25 08:59:00 +02:00
Justin Chadwell
b8739d7441 Merge pull request #1934 from jedevc/use-buildkit-client-wait 2023-07-19 16:23:54 +01:00
Justin Chadwell
23fe02993b Merge pull request #1963 from jedevc/split-to-driver-pairs-fix-type 2023-07-19 15:57:43 +01:00
Justin Chadwell
1d177f00d2 chore: tidy splitToDriverPairs to avoid unneccessary int
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-07-19 14:43:50 +01:00
CrazyMax
ceaba7011f Merge pull request #1938 from jonapich/feature/custom-annotations
kubernetes driver // allow custom annotations and labels
2023-07-19 14:21:12 +02:00
Jonathan Piché
9c06f383ba allow custom annotations and labels into kubernetes manifests
Co-authored-by: Akihiro Suda <suda.kyoto@gmail.com>

Signed-off-by: Jonathan Piché <jpiche@coveo.com>
2023-07-19 07:48:26 -04:00
Justin Chadwell
e11c5e3e96 remote: use buildkit's client.Wait method to bootstrap
This native implementation uses GRPC level waiting, instead of starting
a busy loop. We also a manual max backoff of one second to improve
responsiveness.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-07-19 12:39:19 +01:00
CrazyMax
f5719f3017 Merge pull request #1959 from thaJeztah/update_cli
vendor: github.com/docker/cli v24.0.4
2023-07-19 11:57:02 +02:00
CrazyMax
163babdca7 Merge pull request #1961 from crazy-max/fix-internal-build
build: set remote bake def and remote dockerfile as internal solve
2023-07-19 11:47:52 +02:00
Sebastiaan van Stijn
094d1aded8 commands: NewRootCmd: remove obsolete logrus filter hook
This hook was added in 278f94a8b6 and
72758fef22 to suppress spurious warnings
printed by the CLI's cli/connhelper/commandconn package;
3fb4fb83df/cli/connhelper/commandconn/commandconn.go (L203-L214)

Those logs were removed in a5ebe2282a
so we can remove the hook.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-19 11:04:45 +02:00
CrazyMax
05ef20b434 build: set remote bake def and remote dockerfile as internal solve
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-07-19 04:18:28 +02:00
Sebastiaan van Stijn
cc718b3444 vendor: github.com/docker/cli v24.0.4
full diff: https://github.com/docker/cli/compare/v24.0.2...v24.0.4

notable changes:

- ssh: fix error on commandconn close, add ping and default
- commandconn: return original error while closing

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-18 17:13:42 +02:00
Justin Chadwell
e98e8f6ac9 Merge pull request #1948 from thaJeztah/buildkit_0.12 2023-07-18 15:05:18 +01:00
CrazyMax
36541ed9d5 Merge pull request #1954 from crazy-max/result-handle-internal
build: mark result handle build as internal
2023-07-17 17:05:34 +02:00
CrazyMax
418ea82d3a build: mark result handle build as internal
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-07-17 16:53:12 +02:00
Sebastiaan van Stijn
130bbda00e vendor: github.com/moby/buildkit v0.12.1-0.20230717122532-faa0cc7da353
full diff:

- https://github.com/moby/buildkit/compare/20230620112432...v0.12.0
- https://github.com/moby/buildkit/compare/v0.12.0...faa0cc7da3536923d85b74b2bb2d13c12a6ecc99

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-17 15:37:27 +02:00
Sebastiaan van Stijn
2666bd6996 vendor: github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531
full diff: 8066bb9726...f9a4f7ef65

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-17 15:35:43 +02:00
Sebastiaan van Stijn
ff2c8da803 vendor: github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb
full diff: 9e7a6df485...36ef4d8c0d

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-17 15:35:43 +02:00
Sebastiaan van Stijn
e094296f37 vendor: github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb
full diff: 4e3ac2762d...02993c407b

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-17 15:35:40 +02:00
Justin Chadwell
7c3b77fb36 Merge pull request #1950 from thaJeztah/remove_imageutil_dead_code 2023-07-17 12:26:05 +01:00
CrazyMax
fb4c4f07ca Merge pull request #1941 from crazy-max/fix-kube-config
k8s: fix missing kubeconfig check from endpoint
2023-07-17 12:36:27 +02:00
Sebastiaan van Stijn
b9e25e82cf util/imagetools: remove unused Resolver.ImageConfig
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-07-17 12:35:42 +02:00
CrazyMax
089036da29 Merge pull request #1946 from crazy-max/update-go
update go to 1.20.6
2023-07-17 12:01:26 +02:00
CrazyMax
1123bfed10 hack(generated-files): bump golang image to bookworm
#7 [internal] load metadata for docker.io/library/golang:1.20.6-buster
#7 ERROR: docker.io/library/golang:1.20.6-buster: not found

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-07-17 11:18:37 +02:00
CrazyMax
7f2293308b update go to 1.20.6
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-07-17 10:30:00 +02:00
CrazyMax
a65131f9d3 Merge pull request #1945 from crazy-max/bump-docker
vendor: github.com/docker/docker@24.0 36e9e79
2023-07-17 10:29:40 +02:00
CrazyMax
8a3a646c61 vendor: github.com/docker/docker@24.0 36e9e79
client: define a "dummy" hostname to use for local connections
fixes "http: invalid Host header" errors when compiling with go1.20.6
or go1.19.11

full diff: https://github.com/docker/docker/compare/v24.0.2...36e9e796c6fc

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-07-17 10:06:04 +02:00
CrazyMax
4384947be1 k8s: fix missing kubeconfig check from endpoint
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-07-15 21:51:56 +02:00
Tõnis Tiigi
69421182ca Merge pull request #1891 from droopy4096/auth-token
Add Bearer token support
2023-07-12 11:57:47 -07:00
Justin Chadwell
068382f5df Merge pull request #1936 from jedevc/hack-set-go-version-to-1.20.5 2023-07-12 14:49:59 +01:00
Justin Chadwell
c4bec05466 hack: force go version to 1.20.5
A temporary workaround for "http: invalid Host header" introduced in
go 1.20.6.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-07-12 14:31:23 +01:00
CrazyMax
89e1ac0a6e Merge pull request #1894 from crazy-max/fix-host-gateway
build: fix host-gateway handling
2023-07-03 21:53:27 +02:00
Justin Chadwell
b84e0e11b4 Merge pull request #1918 from crazy-max/docs-hidden-fix 2023-07-03 11:50:04 +01:00
Justin Chadwell
d95f5f8f3b Merge pull request #1925 from dvdksn/test/build-progress 2023-07-03 10:48:52 +01:00
David Karlsson
b4c0941683 tests: add basic build progress test
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2023-07-02 21:09:33 +02:00
Justin Chadwell
cf9798cede Merge pull request #1919 from crazy-max/fix-build-details-link 2023-06-30 13:51:23 +01:00
CrazyMax
20d2501edc test: build details output
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-30 13:48:02 +02:00
CrazyMax
d45601fdc6 build: missing newline when printing build details on error
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-30 13:48:02 +02:00
CrazyMax
c81a9a89cf Merge pull request #1913 from yastanotheruser/master
Controller: Include CgroupParent in build.Options
2023-06-30 00:07:15 +02:00
CrazyMax
87b9f9ecfb docs: update generated content
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-27 17:21:05 +02:00
CrazyMax
cbc473359a vendor: update cli-docs-tool to 0.6.0
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-27 17:21:04 +02:00
Justin Chadwell
2eba60db75 Merge pull request #1916 from jedevc/add-local-bake-test 2023-06-27 11:28:47 +01:00
Justin Chadwell
0dcbed3f53 tests: add simple local bake test
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-06-27 11:16:44 +01:00
Kohei Tokunaga
ca08eb65e2 docs: debug: update the output of help command to the latest message
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
2023-06-27 15:17:01 +09:00
Kohei Tokunaga
6f37d9bee7 monitor: attach: fix typo in long help message
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
2023-06-27 15:16:32 +09:00
Jhan S. Álvarez
e65f6b8c8b controller: include CgroupParent in build.Options
Signed-off-by: Jhan S. Álvarez <alvarezpcuser@gmail.com>
2023-06-26 23:18:53 -05:00
CrazyMax
707dc43d55 Merge pull request #1903 from crazy-max/fix-bake-compose-profiles
bake: ignore profiles in compose definitions
2023-06-26 15:02:53 +02:00
CrazyMax
8cbb7a9319 build: fix host-gateway handling
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-24 17:47:48 +02:00
CrazyMax
4f5a56aadb Merge pull request #1904 from thaJeztah/cleanup_ParseEntitlements
utils/buildflags: ParseEntitlements(): use BuildKit's parsing
2023-06-23 14:26:44 +02:00
Sebastiaan van Stijn
399beb53d9 utils/buildflags: ParseEntitlements(): use BuildKit's parsing
Use buildkit's parsing of entitlements to make sure that accepted
values match what's accepted by BuildKit.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-06-23 10:44:30 +02:00
Sebastiaan van Stijn
7dec9fd6e7 update flag-description for --cgroup-parent
This attempts to make it clearer that the --cgroup-parent option is only used
for the containers used during build. Instead of mentioning "build container",
I opted for using "RUN instructions" (to match the --network description),
although this may not be ideal (as it assumes the "Dockerfile" front-end, which
of course may not be the case).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-06-23 10:28:50 +02:00
CrazyMax
120f3a8918 bake: ignore profiles in compose definitions
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-22 17:44:35 +02:00
CrazyMax
bd672eaf5b Merge pull request #1886 from crazy-max/docker-local
build: prefer local image resolution for docker driver
2023-06-21 11:20:24 +02:00
CrazyMax
c2500ea2d8 build: prefer local image resolution for docker driver
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-21 11:05:06 +02:00
Justin Chadwell
a4663b4b2e Merge pull request #1900 from cyphar/build-go_extra_flags 2023-06-21 09:59:19 +01:00
Aleksa Sarai
57c618b83a build: add GO_EXTRA_FLAGS argument
This is useful for setting things like -buildmode=pie when packaging
docker-buildx for distributions.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2023-06-21 18:48:05 +10:00
CrazyMax
b3a4f95110 Merge pull request #1897 from crazy-max/test-containerd-snap
test: register docker worker with containerd snapshotter
2023-06-21 00:11:31 +02:00
CrazyMax
28a1eb3527 test: fix testImageIDOutput
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-20 17:04:21 +02:00
CrazyMax
75ecc15958 test: fix inspect and ls
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-20 17:04:21 +02:00
CrazyMax
2235ebce2f test: register docker worker with containerd snapshotter
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-20 17:04:21 +02:00
CrazyMax
7147463418 dockerfile: update docker to 24.0.2
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-20 16:50:38 +02:00
Justin Chadwell
010e4c8d54 Merge pull request #1890 from jedevc/tests-share-docker-container-backend 2023-06-20 14:24:09 +01:00
Justin Chadwell
6f394a0691 tests: set a dedicated buildx config dir for each worker
This should help reduce any unexpected config conflict between workers.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-06-20 12:40:45 +01:00
Justin Chadwell
efd7279118 ci: run docker-container tests in parallel
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-06-20 12:28:51 +01:00
Justin Chadwell
601056f3a7 tests: share single docker between docker-container backends
This means that we can run our docker-container tests in parallel again,
which can help speed up our test runs by a *significant* amount.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-06-20 12:28:49 +01:00
Justin Chadwell
0a7f96cbfb vendor: update buildkit to master@2d91ddcceedc
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-06-20 12:27:46 +01:00
CrazyMax
1c530c2fe0 Merge pull request #1896 from dvdksn/docs/add-experimental-debugmonitor
docs: add experimental annotation for debug-shell command
2023-06-20 12:46:26 +02:00
David Karlsson
1e576dd7c6 chore: make docs
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2023-06-20 12:05:30 +02:00
CrazyMax
7a5472153b docs: set experimental annotation
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-20 11:42:02 +02:00
Dmitry Makovey
b986ce566b Add Bearer token
Signed-off-by: Dmitry Makovey <dmakovey@gitlab.com>
2023-06-16 14:55:09 -06:00
CrazyMax
daba16f4be Merge pull request #1879 from crazy-max/fix-ctx-validation
builder: skip name validation for docker context
2023-06-15 14:05:37 +02:00
CrazyMax
ee36e2264e Merge pull request #1880 from jedevc/fix-dockerfile-cwd-join
bake: fix incorrect dockerfile resolution against `cwd://` context
2023-06-15 14:05:13 +02:00
CrazyMax
329e98d9f0 Merge pull request #1883 from docker/dependabot/github_actions/peter-evans/create-pull-request-5.0.2
build(deps): Bump peter-evans/create-pull-request from 5.0.1 to 5.0.2
2023-06-15 13:55:26 +02:00
dependabot[bot]
f4513f7028 build(deps): Bump peter-evans/create-pull-request from 5.0.1 to 5.0.2
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 5.0.1 to 5.0.2.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](284f54f989...153407881e)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-14 18:59:43 +00:00
CrazyMax
b1c5449428 builder: skip name validation for docker context
Although a builder from the store cannot be created unless
it has a valid name, this is not the case for a Docker context.

We should skip name validation when checking a node from the
store and fall back to finding one from Docker context instead.

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-14 14:19:30 +02:00
Justin Chadwell
431732f5d1 bake: fix incorrect dockerfile resolution against cwd:// context
We need to resolve the strip the cwd:// prefix before attempting to
resolve the dockerfile. Otherwise, we'll get the cwd:// prefix in the
dockerfile name, which isn't stripped out later.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-06-14 12:18:53 +01:00
CrazyMax
687feca9e8 Merge pull request #1877 from jedevc/cache-dockerutil-features
dockerutil: cache feature collection
2023-06-13 11:42:22 +02:00
Justin Chadwell
d4a2c8d0c3 dockerutil: cache feature collection
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-06-13 09:47:38 +01:00
Justin Chadwell
bef42b2441 Merge pull request #1876 from tonistiigi/remove-history-request 2023-06-13 09:38:05 +01:00
CrazyMax
2de333fdd3 check history api support once
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-06-13 10:29:22 +02:00
Tonis Tiigi
1138789f20 avoid extra client for history API detection
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2023-06-12 17:39:09 -07:00
Justin Chadwell
1f4ac09ffb Merge pull request #1874 from thaJeztah/bump_engine_24.0.2 2023-06-09 11:39:13 +01:00
CrazyMax
26a8ffb393 Merge pull request #1873 from jedevc/vendor-buildkit-master
vendor: update buildkit to master@67a08623b95a
2023-06-09 12:14:11 +02:00
CrazyMax
9b7aada99b Merge pull request #1716 from distorhead/use-docker-cli-in-stream
build(cli): allow passing in-stream using command.Cli
2023-06-09 12:11:47 +02:00
Sebastiaan van Stijn
fd6207695b vendor: github.com/docker/cli v24.0.2
no changes in vendored files

full diff: https://github.com/docker/cli/compare/v24.0.1...v24.0.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-06-09 12:07:44 +02:00
Sebastiaan van Stijn
def96d2bf4 vendor: github.com/docker/docker v24.0.2
no changes in vendored files

full diff: https://github.com/docker/docker/compare/v24.0.1...v24.0.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-06-09 12:07:01 +02:00
Justin Chadwell
f5f00e68ef bake(cli): allow passing in-stream using command.Cli
ReadLocalFiles should allow passing the stdin file as an argument, which
allows us to read from dockerCli.Stdin() to be consistent with other
commands in the same package.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-06-09 10:50:53 +01:00
Justin Chadwell
14aebe713e debug-shell(cli): allow passing in-stream using command.Cli
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-06-09 10:50:35 +01:00
Justin Chadwell
9d2388e6f5 vendor: update buildkit to master@67a08623b95a
Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-06-09 10:36:52 +01:00
Timofey Kirillov
75e2c46295 build(cli): allow passing in-stream using command.Cli
Use command.Cli::In() which is always initialized either to os.Stdin, or to user-specified stream:
* 5be21394cb/cli/command/cli.go (L494)
* https://github.com/docker/cli/blob/master/cli/command/cli_options.go#L16C1-L26

Signed-off-by: Timofey Kirillov <timofey.kirillov@flant.com>
2023-06-09 12:19:02 +03:00
Justin Chadwell
2c02db8db4 Merge pull request #1835 from ktock/long-form-json 2023-06-08 17:10:37 +01:00
Kohei Tokunaga
e304a05d2a docs: monitor: mention about long form flag
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
2023-06-08 17:05:03 +01:00
Kohei Tokunaga
14c1ea0e11 invoke: Allow JSON array for long form flags
This commit allows specifying a JSON array to the long-form arg, entrypoint and
envvars.
Non-JSON-array value can still be specified. Buildx treats the value as a JSON
array only when it can be parsed as a JSON array.

Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
2023-06-08 17:05:02 +01:00
Justin Chadwell
c30bcade2c Merge pull request #1870 from tianon/invoke-entrypoint-fixes 2023-06-08 16:03:24 +01:00
Tianon Gravi
62bfb19db4 Fix a couple --invoke entrypoint interaction bugs
When running `--invoke` against images that have `Cmd` set, the interactions with `Entrypoint` start to cause issues like the following:

    /usr/local/bin/bash: /usr/local/bin/bash: cannot execute binary file

Or:

    sh: can't open 'bash': No such file or directory

This patch fixes those by explicitly setting `Cmd` to be empty if it is unspecified and `Entrypoint` is being set, which matches `docker`'s behavior:

    $ docker image inspect --format '{{ json .Config.Entrypoint }} + {{ json .Config.Cmd }}' bash
    ["docker-entrypoint.sh"] + ["bash"]
    $ docker create --name foo --entrypoint bash bash
    $ docker container inspect --format '{{ json .Config.Entrypoint }} + {{ json .Config.Cmd }}' foo
    ["bash"] + null
    $ docker rm foo
    $ docker create --name foo bash ls
    $ docker container inspect --format '{{ json .Config.Entrypoint }} + {{ json .Config.Cmd }}' foo
    ["docker-entrypoint.sh"] + ["ls"]

(There are still some weird edge cases in the interaction between the `InvokeConfig` and the original image config, but this fixes the most irritating for me and the rest are going to be deeper changes that are possibly less acceptable. 😅)

Signed-off-by: Tianon Gravi <admwiggin@gmail.com>
2023-06-07 16:33:28 -07:00
Justin Chadwell
d0bff18cee commands: consume DEBUG environment variable
When running in standalone mode, the --debug flag passed to docker
cannot be passed. The docker cli also supports a DEBUG env var, however,
in standalone mode this won't be consumed.

This patch reads the contents of the DEBUG environment variable, and
enables debugging logs when it's been set.

Signed-off-by: Justin Chadwell <me@jedevc.com>
2023-05-22 09:52:23 +01:00
CrazyMax
8ad30d0a35 docs: update since buildinfo removal
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-03-15 17:00:54 +01:00
272 changed files with 9383 additions and 2215 deletions

View File

@@ -0,0 +1,25 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/go
{
"name": "Go",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/go:1-1.21-bullseye",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
}
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "go version",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

View File

@@ -31,7 +31,7 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
@@ -66,6 +66,7 @@ jobs:
matrix:
worker:
- docker
- docker\+containerd # same as docker, but with containerd snapshotter
- docker-container
- remote
pkg:
@@ -76,7 +77,9 @@ 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
@@ -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,7 +162,7 @@ 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
@@ -194,7 +197,7 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
@@ -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,7 +283,7 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2

View File

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

View File

@@ -26,7 +26,7 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

View File

@@ -25,7 +25,7 @@ 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
@@ -96,7 +96,7 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2

View File

@@ -30,7 +30,7 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

View File

@@ -1,14 +1,13 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.20
ARG GO_VERSION=1.20.7
ARG XX_VERSION=1.2.1
ARG DOCKERD_VERSION=20.10.14
ARG DOCKER_VERSION=24.0.2
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/
@@ -95,14 +121,14 @@ RUN --mount=from=binaries \
--mount=type=bind,from=buildx-version,source=/buildx-version,target=/buildx-version <<EOT
set -e
mkdir -p /out
cp buildx* "/out/buildx-$(cat /buildx-version/version).$(echo $TARGETPLATFORM | sed 's/\//-/g')$(ls buildx* | sed -e 's/^buildx//')"
cp buildx* "/out/buildx"
EOT
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

View File

@@ -71,8 +71,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 +149,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 +241,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/)

View File

@@ -55,7 +55,7 @@ func defaultFilenames() []string {
return names
}
func ReadLocalFiles(names []string) ([]File, error) {
func ReadLocalFiles(names []string, stdin io.Reader) ([]File, error) {
isDefault := false
if len(names) == 0 {
isDefault = true
@@ -67,7 +67,7 @@ func ReadLocalFiles(names []string) ([]File, error) {
var dt []byte
var err error
if n == "-" {
dt, err = io.ReadAll(os.Stdin)
dt, err = io.ReadAll(stdin)
if err != nil {
return nil, err
}
@@ -587,9 +587,9 @@ 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"`
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"`
@@ -1048,12 +1048,12 @@ 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.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://"))}

View File

@@ -295,6 +295,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 +306,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 +345,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 +370,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"])
@@ -386,18 +392,19 @@ 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")
require.Equal(t, "test", *m["app"].Dockerfile)
require.Equal(t, "foo", *m["app"].Context)
require.Equal(t, "foo/test", bo["app"].Inputs.DockerfilePath)
require.Equal(t, "foo", bo["app"].Inputs.ContextPath)
}
func TestOverrideMerge(t *testing.T) {
@@ -542,6 +549,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 +564,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 +1408,7 @@ func TestReadLocalFilesDefault(t *testing.T) {
for _, tf := range tt.filenames {
require.NoError(t, os.WriteFile(tf, []byte(tf), 0644))
}
files, err := ReadLocalFiles(nil)
files, err := ReadLocalFiles(nil, nil)
require.NoError(t, err)
if len(files) == 0 {
require.Equal(t, len(tt.expected), len(files))

View File

@@ -37,6 +37,7 @@ func ParseCompose(cfgs []compose.ConfigFile, envs map[string]string) (*Config, e
}, func(options *loader.Options) {
options.SetProjectName("bake", false)
options.SkipNormalization = true
options.Profiles = []string{"*"}
})
if err != nil {
return nil, err

View File

@@ -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,66 @@ 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)
}
// 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) {

View File

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

View File

@@ -267,11 +267,11 @@ func resolveDriversBase(ctx context.Context, nodes []builder.Node, opt map[strin
}
undetectedPlatform := false
allPlatforms := map[string]int{}
allPlatforms := map[string]struct{}{}
for _, opt := range opt {
for _, p := range opt.Platforms {
k := platforms.Format(p)
allPlatforms[k] = -1
allPlatforms[k] = struct{}{}
if _, ok := availablePlatforms[k]; !ok {
undetectedPlatform = true
}
@@ -454,7 +454,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")
@@ -593,7 +593,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
@@ -642,7 +645,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
}
@@ -734,7 +737,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
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]
@@ -948,7 +951,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
} else {
rr, err = c.Build(ctx, so, "buildx", buildFunc, ch)
}
if node.Driver.Features(ctx)[driver.HistoryAPI] && desktop.BuildBackendEnabled() {
if desktop.BuildBackendEnabled() && node.Driver.HistoryAPISupported(ctx) {
buildRef := fmt.Sprintf("%s/%s/%s", node.Builder, node.Name, so.Ref)
if err != nil {
return &desktop.ErrorWithBuildRef{
@@ -1098,7 +1101,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
}
@@ -1262,7 +1265,7 @@ func createTempDockerfile(r io.Reader) (string, error) {
return dir, err
}
func LoadInputs(ctx context.Context, d driver.Driver, inp Inputs, pw progress.Writer, target *client.SolveOpt) (func(), error) {
func LoadInputs(ctx context.Context, d *driver.DriverHandle, inp Inputs, pw progress.Writer, target *client.SolveOpt) (func(), error) {
if inp.ContextPath == "" {
return nil, errors.New("please specify build context (e.g. \".\" for the current directory)")
}

View File

@@ -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")

View File

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

View File

@@ -13,7 +13,7 @@ import (
"github.com/pkg/errors"
)
func createTempDockerfileFromURL(ctx context.Context, d driver.Driver, url string, pw progress.Writer) (string, error) {
func createTempDockerfileFromURL(ctx context.Context, d *driver.DriverHandle, url string, pw progress.Writer) (string, error) {
c, err := driver.Boot(ctx, ctx, d, pw)
if err != nil {
return "", err
@@ -21,7 +21,7 @@ func createTempDockerfileFromURL(ctx context.Context, d driver.Driver, url strin
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

View File

@@ -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)
}

View File

@@ -22,7 +22,7 @@ import (
type Node struct {
store.Node
Builder string
Driver driver.Driver
Driver *driver.DriverHandle
DriverInfo *driver.Info
Platforms []ocispecs.Platform
GCPolicy []client.PruneInfo
@@ -82,12 +82,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 +109,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.SecurityOpts, n.Platforms, b.opts.contextPathHash)
if err != nil {
node.Err = err
return nil

View File

@@ -146,7 +146,7 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com
if url != "" {
files, inp, err = bake.ReadRemoteFiles(ctx, nodes, url, in.files, printer)
} else {
files, err = bake.ReadLocalFiles(in.files)
files, err = bake.ReadLocalFiles(in.files, dockerCli.In())
}
if err != nil {
return err

View File

@@ -312,7 +312,7 @@ func getImageID(resp map[string]string) string {
}
func runBasicBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, options buildOptions, printer *progress.Printer) (*client.SolveResponse, error) {
resp, res, err := cbuild.RunBuild(ctx, dockerCli, *opts, os.Stdin, printer, false)
resp, res, err := cbuild.RunBuild(ctx, dockerCli, *opts, dockerCli.In(), printer, false)
if res != nil {
res.Done()
}
@@ -346,7 +346,7 @@ func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *contro
var retErr error
var resp *client.SolveResponse
f := ioset.NewSingleForwarder()
f.SetReader(os.Stdin)
f.SetReader(dockerCli.In())
if !options.noBuild {
pr, pw := io.Pipe()
f.SetWriter(pw, func() io.WriteCloser {
@@ -464,7 +464,7 @@ func buildCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
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 +487,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 +515,14 @@ 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]")
flags.StringVar(&invokeFlag, "invoke", "", "Invoke a command after the build")
flags.SetAnnotation("invoke", "experimentalCLI", nil)
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 +545,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")
@@ -692,6 +698,7 @@ func (cfg *invokeConfig) needsMonitor(retErr error) bool {
func parseInvokeConfig(invoke string) (cfg invokeConfig, err error) {
cfg.invokeFlag = invoke
cfg.Tty = true
cfg.NoCmd = true
switch invoke {
case "default", "debug-shell":
return cfg, nil
@@ -700,16 +707,19 @@ func parseInvokeConfig(invoke string) (cfg invokeConfig, err error) {
// 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 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]}
cfg.NoCmd = false
return cfg, nil
}
cfg.NoUser = true
@@ -723,11 +733,16 @@ func parseInvokeConfig(invoke string) (cfg invokeConfig, err error) {
value := parts[1]
switch key {
case "args":
cfg.Cmd = append(cfg.Cmd, value) // TODO: support JSON
cfg.Cmd = append(cfg.Cmd, maybeJSONArray(value)...)
cfg.NoCmd = false
case "entrypoint":
cfg.Entrypoint = append(cfg.Entrypoint, value) // TODO: support JSON
cfg.Entrypoint = append(cfg.Entrypoint, maybeJSONArray(value)...)
if cfg.Cmd == nil {
cfg.Cmd = []string{}
cfg.NoCmd = false
}
case "env":
cfg.Env = append(cfg.Env, value)
cfg.Env = append(cfg.Env, maybeJSONArray(value)...)
case "user":
cfg.User = value
cfg.NoUser = false
@@ -746,6 +761,14 @@ func parseInvokeConfig(invoke string) (cfg invokeConfig, err error) {
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 {
result := make(map[string]string, len(values))
for _, value := range values {

View File

@@ -42,6 +42,7 @@ type createOptions struct {
flags string
configFile string
driverOpts []string
securityOpts []string
bootstrap bool
// upgrade bool // perform upgrade of the driver
}
@@ -239,6 +240,11 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
return err
}
s, err := csvToMap(in.securityOpts)
if err != nil {
return err
}
if in.configFile == "" {
// if buildkit config is not provided, check if the default one is
// available and use it
@@ -248,7 +254,7 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
}
}
if err := ng.Update(in.nodeName, ep, in.platform, setEp, in.actionAppend, flags, in.configFile, m); err != nil {
if err := ng.Update(in.nodeName, ep, in.platform, setEp, in.actionAppend, flags, in.configFile, m, s); err != nil {
return err
}
}
@@ -340,6 +346,7 @@ func createCmd(dockerCli command.Cli) *cobra.Command {
flags.StringVar(&options.configFile, "config", "", "BuildKit config file")
flags.StringArrayVar(&options.platform, "platform", []string{}, "Fixed platforms for current node")
flags.StringArrayVar(&options.driverOpts, "driver-opt", []string{}, "Options for the driver")
flags.StringArrayVar(&options.securityOpts, "security-opt", []string{}, "Options for the security profile of driver")
flags.BoolVar(&options.bootstrap, "bootstrap", false, "Boot builder after creation")
flags.BoolVar(&options.actionAppend, "append", false, "Append a node to builder instead of changing it")

View File

@@ -24,6 +24,9 @@ func debugShellCmd(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "debug-shell",
Short: "Start a monitor",
Annotations: map[string]string{
"experimentalCLI": "",
},
RunE: func(cmd *cobra.Command, args []string) error {
printer, err := progress.NewPrinter(context.TODO(), os.Stderr, os.Stderr, progressMode)
if err != nil {
@@ -47,7 +50,7 @@ func debugShellCmd(dockerCli command.Cli) *cobra.Command {
err = monitor.RunMonitor(ctx, "", nil, controllerapi.InvokeConfig{
Tty: true,
}, c, os.Stdin, os.Stdout, os.Stderr, printer)
}, c, dockerCli.In(), os.Stdout, os.Stderr, printer)
con.Reset()
return err
},
@@ -55,9 +58,15 @@ func debugShellCmd(dockerCli command.Cli) *cobra.Command {
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(&options.Root, "root", "", "Specify root directory of server to connect")
flags.SetAnnotation("root", "experimentalCLI", nil)
flags.BoolVar(&options.Detach, "detach", runtime.GOOS == "linux", "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)
flags.StringVar(&progressMode, "progress", "auto", `Set type of progress output ("auto", "plain", "tty"). Use plain to show container output`)
return cmd

View File

@@ -25,6 +25,7 @@ type createOptions struct {
builder string
files []string
tags []string
annotations []string
dryrun bool
actionAppend bool
progress string
@@ -82,6 +83,11 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
return errors.Errorf("no repositories specified, please set a reference in tag or source")
}
ann, err := parseAnnotations(in.annotations)
if err != nil {
return err
}
var defaultRepo *string
if len(repos) == 1 {
for repo := range repos {
@@ -154,7 +160,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, ann)
if err != nil {
return err
}
@@ -264,6 +270,18 @@ func parseSource(in string) (*imagetools.Source, error) {
return &s, nil
}
func parseAnnotations(in []string) (map[string]string, error) {
out := make(map[string]string)
for _, i := range in {
kv := strings.SplitN(i, "=", 2)
if len(kv) != 2 {
return nil, errors.Errorf("invalid annotation %q, expected key=value", in)
}
out[kv[0]] = kv[1]
}
return out, nil
}
func createCmd(dockerCli command.Cli, opts RootOptions) *cobra.Command {
var options createOptions
@@ -283,6 +301,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
}

View File

@@ -82,6 +82,13 @@ func runInspect(dockerCli command.Cli, in inspectOptions) error {
if len(driverOpts) > 0 {
fmt.Fprintf(w, "Driver Options:\t%s\n", strings.Join(driverOpts, " "))
}
var securityOpts []string
for k, v := range n.SecurityOpts {
securityOpts = append(securityOpts, fmt.Sprintf("%s=%q", k, v))
}
if len(securityOpts) > 0 {
fmt.Fprintf(w, "Security Options:\t%s\n", strings.Join(driverOpts, " "))
}
if err := n.Err; err != nil {
fmt.Fprintf(w, "Error:\t%s\n", err.Error())

View File

@@ -11,6 +11,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 +41,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 +58,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
}

View File

@@ -54,6 +54,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
NamedContexts: contexts,
},
BuildArgs: in.BuildArgs,
CgroupParent: in.CgroupParent,
ExtraHosts: in.ExtraHosts,
Labels: in.Labels,
NetworkMode: in.NetworkMode,

View File

@@ -1527,6 +1527,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 +1579,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 +2054,126 @@ func init() {
func init() { proto.RegisterFile("controller.proto", fileDescriptor_ed7f10298fa1d90f) }
var fileDescriptor_ed7f10298fa1d90f = []byte{
// 1881 bytes of a gzipped FileDescriptorProto
// 1890 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,
0xb6, 0xd5, 0xa7, 0x3e, 0xb4, 0x6f, 0x45, 0xbf, 0x47, 0xd1, 0x8f, 0xd0, 0x97, 0xf6, 0x1b, 0xf5,
0x23, 0x14, 0xfb, 0x87, 0x14, 0x69, 0x89, 0xb2, 0xdd, 0x3e, 0x69, 0x67, 0xf8, 0xfb, 0xcd, 0xec,
0x2c, 0x67, 0x67, 0x86, 0x82, 0xf5, 0x1e, 0x0b, 0x44, 0xc8, 0x7c, 0x9f, 0x86, 0x8d, 0x71, 0xc8,
0x04, 0x43, 0x1b, 0xdd, 0x89, 0xe7, 0xf7, 0xaf, 0x1a, 0x89, 0x07, 0x17, 0x5f, 0xda, 0x6f, 0x07,
0x9e, 0x38, 0x9f, 0x74, 0x1b, 0x3d, 0x36, 0x6a, 0x8e, 0x58, 0x77, 0xda, 0x54, 0xa8, 0xa1, 0x27,
0x9a, 0xee, 0xd8, 0x6b, 0x72, 0x1a, 0x5e, 0x78, 0x3d, 0xca, 0x9b, 0x86, 0x14, 0xfd, 0x6a, 0x93,
0xf6, 0xeb, 0x4c, 0x32, 0x67, 0x93, 0xb0, 0x47, 0xc7, 0xcc, 0xf7, 0x7a, 0xd3, 0xe6, 0xb8, 0xdb,
0xd4, 0x2b, 0x4d, 0x73, 0xea, 0xb0, 0xf1, 0xce, 0xe3, 0xe2, 0x24, 0x64, 0x3d, 0xca, 0x39, 0xe5,
0x84, 0xfe, 0x61, 0x42, 0xb9, 0x40, 0xeb, 0x90, 0x27, 0xf4, 0x0c, 0x5b, 0x9b, 0x56, 0xbd, 0x42,
0xe4, 0xd2, 0x39, 0x81, 0x07, 0xd7, 0x90, 0x7c, 0xcc, 0x02, 0x4e, 0xd1, 0x36, 0xac, 0x1c, 0x06,
0x67, 0x8c, 0x63, 0x6b, 0x33, 0x5f, 0xaf, 0x6e, 0x3d, 0x6b, 0x2c, 0x0a, 0xae, 0x61, 0x78, 0x12,
0x49, 0x34, 0xde, 0xe1, 0x50, 0x4d, 0x68, 0xd1, 0x13, 0xa8, 0x44, 0xe2, 0x9e, 0x71, 0x3c, 0x53,
0xa0, 0x36, 0xac, 0x1e, 0x06, 0x17, 0x6c, 0x48, 0x5b, 0x2c, 0x38, 0xf3, 0x06, 0x38, 0xb7, 0x69,
0xd5, 0xab, 0x5b, 0xce, 0x62, 0x67, 0x49, 0x24, 0x49, 0xf1, 0x9c, 0xef, 0x01, 0xef, 0x79, 0xbc,
0xc7, 0x82, 0x80, 0xf6, 0xa2, 0x60, 0x32, 0x83, 0x4e, 0xef, 0x29, 0x77, 0x6d, 0x4f, 0xce, 0x63,
0x78, 0xb4, 0xc0, 0x96, 0x3e, 0x16, 0xe7, 0xf7, 0xb0, 0xba, 0x2b, 0xf7, 0x96, 0x6d, 0xfc, 0x5b,
0x28, 0x1d, 0x8f, 0x85, 0xc7, 0x02, 0xbe, 0x3c, 0x1a, 0x65, 0xc6, 0x20, 0x49, 0x44, 0x71, 0xfe,
0x55, 0x35, 0x0e, 0x8c, 0x02, 0x6d, 0x42, 0xb5, 0xc5, 0x02, 0x41, 0xaf, 0xc4, 0x89, 0x2b, 0xce,
0x8d, 0xa3, 0xa4, 0x0a, 0x7d, 0x0e, 0x6b, 0x7b, 0xac, 0x37, 0xa4, 0xe1, 0x99, 0xe7, 0xd3, 0x23,
0x77, 0x44, 0x4d, 0x48, 0xd7, 0xb4, 0xe8, 0x3b, 0x19, 0xb5, 0x17, 0x88, 0xf6, 0x24, 0xe8, 0xe1,
0xbc, 0xda, 0xda, 0xd3, 0xac, 0xb7, 0x6a, 0x60, 0x64, 0xc6, 0x40, 0xbf, 0x83, 0x9a, 0x34, 0xd3,
0x37, 0xae, 0x39, 0x2e, 0xa8, 0xc4, 0x78, 0x7d, 0x73, 0x74, 0x8d, 0x14, 0x6f, 0x3f, 0x10, 0xe1,
0x94, 0xa4, 0x6d, 0xa1, 0x0d, 0x58, 0xd9, 0xf1, 0x7d, 0x76, 0x89, 0x57, 0x36, 0xf3, 0xf5, 0x0a,
0xd1, 0x02, 0xfa, 0x15, 0x94, 0x76, 0x84, 0xa0, 0x5c, 0x70, 0x5c, 0x54, 0xce, 0x9e, 0x2c, 0x76,
0xa6, 0x41, 0x24, 0x02, 0xa3, 0x63, 0xa8, 0x28, 0xff, 0x3b, 0xe1, 0x80, 0xe3, 0x92, 0x62, 0x7e,
0x79, 0x8b, 0x6d, 0xc6, 0x1c, 0xbd, 0xc5, 0x99, 0x0d, 0xb4, 0x0f, 0x95, 0x96, 0xdb, 0x3b, 0xa7,
0xed, 0x90, 0x8d, 0x70, 0x59, 0x19, 0xfc, 0xd9, 0x62, 0x83, 0x0a, 0x66, 0x0c, 0x1a, 0x33, 0x31,
0x13, 0xed, 0x40, 0x49, 0x09, 0xa7, 0x0c, 0x57, 0xee, 0x66, 0x24, 0xe2, 0x21, 0x07, 0x56, 0x5b,
0x83, 0x90, 0x4d, 0xc6, 0x27, 0x6e, 0x48, 0x03, 0x81, 0x41, 0xbd, 0xea, 0x94, 0x0e, 0xbd, 0x85,
0xd2, 0xfe, 0xd5, 0x98, 0x85, 0x82, 0xe3, 0xea, 0xb2, 0xcb, 0xab, 0x41, 0xc6, 0x81, 0x61, 0xa0,
0xcf, 0x00, 0xf6, 0xaf, 0x44, 0xe8, 0x1e, 0x30, 0x79, 0xec, 0xab, 0xea, 0x75, 0x24, 0x34, 0xa8,
0x0d, 0xc5, 0x77, 0x6e, 0x97, 0xfa, 0x1c, 0xd7, 0x94, 0xed, 0xc6, 0x2d, 0x0e, 0x56, 0x13, 0xb4,
0x23, 0xc3, 0x96, 0x79, 0x7d, 0x44, 0xc5, 0x25, 0x0b, 0x87, 0xef, 0x59, 0x9f, 0xe2, 0x35, 0x9d,
0xd7, 0x09, 0x15, 0x7a, 0x01, 0xb5, 0x23, 0xa6, 0x0f, 0xcf, 0xf3, 0x05, 0x0d, 0xf1, 0x3d, 0xb5,
0x99, 0xb4, 0x52, 0xdd, 0x65, 0xdf, 0x15, 0x67, 0x2c, 0x1c, 0x71, 0xbc, 0xae, 0x10, 0x33, 0x85,
0xcc, 0xa0, 0x0e, 0xed, 0x85, 0x54, 0x70, 0x7c, 0x7f, 0x59, 0x06, 0x69, 0x10, 0x89, 0xc0, 0x08,
0x43, 0xa9, 0x73, 0x3e, 0xea, 0x78, 0x7f, 0xa4, 0x18, 0x6d, 0x5a, 0xf5, 0x3c, 0x89, 0x44, 0xf4,
0x0a, 0xf2, 0x9d, 0xce, 0x01, 0xfe, 0xb1, 0xb2, 0xf6, 0x28, 0xc3, 0x5a, 0xe7, 0x80, 0x48, 0x14,
0x42, 0x50, 0x38, 0x75, 0x07, 0x1c, 0x6f, 0xa8, 0x7d, 0xa9, 0x35, 0x7a, 0x08, 0xc5, 0x53, 0x37,
0x1c, 0x50, 0x81, 0x1f, 0xa8, 0x98, 0x8d, 0x84, 0xde, 0x40, 0xe9, 0x83, 0xef, 0x8d, 0x3c, 0xc1,
0xf1, 0xc3, 0x65, 0x97, 0x53, 0x83, 0x8e, 0xc7, 0x82, 0x44, 0x78, 0xb9, 0x5b, 0x75, 0xde, 0x34,
0xc4, 0x3f, 0x51, 0x36, 0x23, 0x51, 0x3e, 0x31, 0xc7, 0x85, 0xf1, 0xa6, 0x55, 0x2f, 0x93, 0x48,
0x94, 0x5b, 0x3b, 0x99, 0xf8, 0x3e, 0x7e, 0xa4, 0xd4, 0x6a, 0xad, 0xdf, 0xbd, 0x4c, 0x83, 0x93,
0x09, 0x3f, 0xc7, 0xb6, 0x7a, 0x92, 0xd0, 0xcc, 0x9e, 0xbf, 0x63, 0x6e, 0x1f, 0x3f, 0x4e, 0x3e,
0x97, 0x1a, 0x74, 0x08, 0xab, 0x1d, 0xd5, 0x96, 0x4e, 0x54, 0x33, 0xc2, 0x4f, 0x54, 0x1c, 0x2f,
0x1b, 0xb2, 0x73, 0x35, 0xa2, 0xce, 0x25, 0x63, 0x48, 0x36, 0xaf, 0x86, 0x06, 0x93, 0x14, 0xd5,
0xfe, 0x35, 0xa0, 0xf9, 0xaa, 0x21, 0xab, 0xed, 0x90, 0x4e, 0xa3, 0x6a, 0x3b, 0xa4, 0x53, 0x59,
0x38, 0x2e, 0x5c, 0x7f, 0x12, 0xd5, 0x3c, 0x2d, 0x7c, 0x93, 0xfb, 0xda, 0xb2, 0xbf, 0x85, 0xb5,
0xf4, 0x85, 0xbe, 0x13, 0xfb, 0x0d, 0x54, 0x13, 0x59, 0x7b, 0x17, 0xaa, 0xf3, 0x6f, 0x0b, 0xaa,
0x89, 0xab, 0xa5, 0x92, 0x60, 0x3a, 0xa6, 0x86, 0xac, 0xd6, 0x68, 0x17, 0x56, 0x76, 0x84, 0x08,
0x65, 0x8b, 0x90, 0x79, 0xf4, 0x8b, 0x1b, 0x2f, 0x68, 0x43, 0xc1, 0xf5, 0x15, 0xd2, 0x54, 0x79,
0x83, 0xf6, 0x28, 0x17, 0x5e, 0xe0, 0xca, 0x5b, 0xa6, 0x2a, 0x7a, 0x85, 0x24, 0x55, 0xf6, 0xd7,
0x00, 0x33, 0xda, 0x9d, 0x62, 0xf8, 0x87, 0x05, 0xf7, 0xe7, 0xaa, 0xd0, 0xc2, 0x48, 0x0e, 0xd2,
0x91, 0x6c, 0xdd, 0xb2, 0xa2, 0xcd, 0xc7, 0xf3, 0x7f, 0xec, 0xf6, 0x08, 0x8a, 0xba, 0xf4, 0x2f,
0xdc, 0xa1, 0x0d, 0xe5, 0x3d, 0x8f, 0xbb, 0x5d, 0x9f, 0xf6, 0x15, 0xb5, 0x4c, 0x62, 0x59, 0xf5,
0x1d, 0xb5, 0x7b, 0x7d, 0x7a, 0x5a, 0x70, 0xf4, 0x1d, 0x47, 0x6b, 0x90, 0x8b, 0x67, 0x96, 0xdc,
0xe1, 0x9e, 0x04, 0xcb, 0x86, 0xab, 0x43, 0xad, 0x10, 0x2d, 0x38, 0x6d, 0x28, 0xea, 0xaa, 0x31,
0x87, 0xb7, 0xa1, 0xdc, 0xf6, 0x7c, 0xaa, 0xfa, 0xb6, 0xde, 0x73, 0x2c, 0xcb, 0xf0, 0xf6, 0x83,
0x0b, 0xe3, 0x56, 0x2e, 0x9d, 0xed, 0x44, 0x7b, 0x96, 0x71, 0xa8, 0x4e, 0x6e, 0xe2, 0x50, 0xfd,
0xfb, 0x21, 0x14, 0xdb, 0x2c, 0x1c, 0xb9, 0xc2, 0x18, 0x33, 0x92, 0xe3, 0xc0, 0xda, 0x61, 0xc0,
0xc7, 0xb4, 0x27, 0xb2, 0xc7, 0xbc, 0x63, 0xb8, 0x17, 0x63, 0xcc, 0x80, 0x97, 0x98, 0x53, 0xac,
0xbb, 0xcf, 0x29, 0x7f, 0xb7, 0xa0, 0x12, 0x57, 0x22, 0xd4, 0x82, 0xa2, 0x7a, 0x1b, 0xd1, 0xb4,
0xf8, 0xea, 0x86, 0xd2, 0xd5, 0xf8, 0xa8, 0xd0, 0xa6, 0x23, 0x68, 0xaa, 0xfd, 0x03, 0x54, 0x13,
0xea, 0x05, 0x09, 0xb0, 0x95, 0x4c, 0x80, 0xcc, 0x52, 0xae, 0x9d, 0x24, 0xd3, 0x63, 0x0f, 0x8a,
0x5a, 0xb9, 0xf0, 0x58, 0x11, 0x14, 0x0e, 0xdc, 0x50, 0xa7, 0x46, 0x9e, 0xa8, 0xb5, 0xd4, 0x75,
0xd8, 0x99, 0x50, 0xaf, 0x27, 0x4f, 0xd4, 0xda, 0xf9, 0xa7, 0x05, 0x35, 0x33, 0xfa, 0x99, 0x13,
0xa4, 0xb0, 0xae, 0x6f, 0x28, 0x0d, 0x23, 0x9d, 0x89, 0xff, 0xcd, 0x92, 0xa3, 0x8c, 0xa0, 0x8d,
0xeb, 0x5c, 0x7d, 0x1a, 0x73, 0x26, 0xed, 0x16, 0x3c, 0x58, 0x08, 0xbd, 0xd3, 0x15, 0x79, 0x09,
0xf7, 0x67, 0x43, 0x6d, 0x76, 0x9e, 0x6c, 0x00, 0x4a, 0xc2, 0xcc, 0xd0, 0xfb, 0x14, 0xaa, 0xf2,
0x23, 0x21, 0x9b, 0xe6, 0xc0, 0xaa, 0x06, 0x98, 0x93, 0x41, 0x50, 0x18, 0xd2, 0xa9, 0xce, 0x86,
0x0a, 0x51, 0x6b, 0xe7, 0x6f, 0x96, 0x9c, 0xf5, 0xc7, 0x13, 0xf1, 0x9e, 0x72, 0xee, 0x0e, 0x64,
0x02, 0x16, 0x0e, 0x03, 0x4f, 0x98, 0xec, 0xfb, 0x3c, 0x6b, 0xe6, 0x1f, 0x4f, 0x84, 0x84, 0x19,
0xd6, 0xc1, 0x8f, 0x88, 0x62, 0xa1, 0x6d, 0x28, 0xec, 0xb9, 0xc2, 0x35, 0xb9, 0x90, 0x31, 0xe1,
0x48, 0x44, 0x82, 0x28, 0xc5, 0xdd, 0x92, 0xfc, 0xb0, 0x19, 0x4f, 0x84, 0xf3, 0x02, 0xd6, 0xaf,
0x5b, 0x5f, 0x10, 0xda, 0x57, 0x50, 0x4d, 0x58, 0x51, 0xf7, 0xf6, 0xb8, 0xad, 0x00, 0x65, 0x22,
0x97, 0x32, 0xd6, 0x78, 0x23, 0xab, 0xda, 0x87, 0x73, 0x0f, 0x6a, 0xca, 0x74, 0x7c, 0x82, 0x7f,
0xca, 0x41, 0x29, 0x32, 0xb1, 0x9d, 0x8a, 0xfb, 0x59, 0x56, 0xdc, 0xf3, 0x21, 0xbf, 0x86, 0x82,
0xac, 0x1f, 0x26, 0xe4, 0x8c, 0xf1, 0xa0, 0xdd, 0x4f, 0xd0, 0x24, 0x1c, 0x7d, 0x07, 0x45, 0x42,
0xb9, 0x1c, 0x65, 0xf4, 0xd0, 0xff, 0x7c, 0x31, 0x51, 0x63, 0x66, 0x64, 0x43, 0x92, 0xf4, 0x8e,
0x37, 0x08, 0x5c, 0x1f, 0x17, 0x96, 0xd1, 0x35, 0x26, 0x41, 0xd7, 0x8a, 0xd9, 0x71, 0xff, 0xc5,
0x82, 0xea, 0xd2, 0xa3, 0x5e, 0xfe, 0x59, 0x36, 0xf7, 0xa9, 0x98, 0xff, 0x1f, 0x3f, 0x15, 0xff,
0x9c, 0x4b, 0x1b, 0x52, 0x53, 0x8d, 0xbc, 0x4f, 0x63, 0xe6, 0x05, 0xc2, 0xa4, 0x6c, 0x42, 0x23,
0x37, 0xda, 0x1a, 0xf5, 0x4d, 0xd1, 0x97, 0x4b, 0x79, 0xcd, 0x8e, 0x98, 0xd4, 0x55, 0x55, 0x1a,
0x68, 0x61, 0x56, 0xd2, 0xf3, 0xa6, 0xa4, 0xcb, 0xd4, 0xf8, 0xc0, 0x69, 0xa8, 0x0e, 0xae, 0x42,
0xd4, 0x5a, 0x56, 0xf1, 0x23, 0xa6, 0xb4, 0x2b, 0x8a, 0x6c, 0x24, 0xe5, 0xe5, 0xb2, 0x8f, 0x8b,
0xfa, 0x38, 0x5a, 0x97, 0x91, 0x97, 0xcb, 0x3e, 0x2e, 0xc5, 0x5e, 0x2e, 0x95, 0x97, 0x53, 0x31,
0xc5, 0x65, 0x9d, 0x80, 0xa7, 0x62, 0x2a, 0xdb, 0x0c, 0x61, 0xbe, 0xdf, 0x75, 0x7b, 0x43, 0x5c,
0xd1, 0xfd, 0x2d, 0x92, 0xe5, 0xfc, 0x27, 0xcf, 0xdc, 0x73, 0x7d, 0xf5, 0xa5, 0x50, 0x26, 0x91,
0xe8, 0xec, 0x40, 0x25, 0x4e, 0x15, 0xd9, 0xb9, 0xda, 0x7d, 0xf5, 0x2a, 0x6a, 0x24, 0xd7, 0xee,
0x47, 0x59, 0x9e, 0x9b, 0xcf, 0xf2, 0x7c, 0x22, 0xcb, 0xb7, 0xa1, 0x96, 0x4a, 0x1a, 0x09, 0x22,
0xec, 0x92, 0x1b, 0x43, 0x6a, 0x2d, 0x75, 0x2d, 0xe6, 0xeb, 0x6f, 0xe1, 0x1a, 0x51, 0x6b, 0xe7,
0x39, 0xd4, 0x52, 0xe9, 0xb2, 0xa8, 0x2e, 0x3b, 0xcf, 0xa0, 0xd6, 0x11, 0xae, 0x98, 0x2c, 0xf9,
0xf3, 0xe2, 0x3f, 0x16, 0xac, 0x45, 0x18, 0x53, 0x79, 0x7e, 0x09, 0xe5, 0x0b, 0x1a, 0x0a, 0x7a,
0x15, 0xf7, 0x22, 0x3c, 0x3f, 0x7e, 0x7e, 0x54, 0x08, 0x12, 0x23, 0xd1, 0x37, 0x50, 0xe6, 0xca,
0x0e, 0x8d, 0xe6, 0x98, 0xcf, 0xb2, 0x58, 0xc6, 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, 0x0d, 0xfd, 0x34, 0x8b, 0xf4, 0x83, 0xc6, 0x91, 0x98, 0xe0,
0xd4, 0xe4, 0x25, 0x3a, 0x63, 0xe6, 0x4c, 0x9c, 0xdf, 0xc8, 0x5c, 0x96, 0xa2, 0x09, 0xff, 0x10,
0x6a, 0xfa, 0x3e, 0x7c, 0xa4, 0x21, 0x97, 0x53, 0xa1, 0xb5, 0xec, 0xce, 0xee, 0x26, 0xa1, 0x24,
0xcd, 0x74, 0x3e, 0x99, 0x76, 0x17, 0x29, 0x64, 0x2e, 0x8d, 0xdd, 0xde, 0xd0, 0x1d, 0x44, 0xef,
0x29, 0x12, 0xe5, 0x93, 0x0b, 0xe3, 0x4f, 0x5f, 0xdb, 0x48, 0x94, 0xb9, 0x19, 0xd2, 0x0b, 0x8f,
0xcf, 0x06, 0xd4, 0x58, 0xde, 0xfa, 0x6b, 0x09, 0xa0, 0x15, 0xef, 0x07, 0x9d, 0xc0, 0x8a, 0xf2,
0x87, 0x9c, 0xa5, 0xcd, 0x53, 0xc5, 0x6d, 0x3f, 0xbf, 0x45, 0x83, 0x45, 0x1f, 0x65, 0xf2, 0xab,
0xa1, 0x07, 0xbd, 0xc8, 0x2a, 0x13, 0xc9, 0xb9, 0xc9, 0x7e, 0x79, 0x03, 0xca, 0xd8, 0xfd, 0x00,
0x45, 0x9d, 0x05, 0x28, 0xab, 0x16, 0x26, 0xf3, 0xd6, 0x7e, 0xb1, 0x1c, 0xa4, 0x8d, 0x7e, 0x61,
0x21, 0x62, 0x2a, 0x25, 0x72, 0x96, 0xb4, 0x42, 0x73, 0x63, 0xb2, 0x0e, 0x20, 0xd5, 0x75, 0xea,
0x16, 0xfa, 0x1e, 0x8a, 0xba, 0xd6, 0xa1, 0x9f, 0x2e, 0x26, 0x44, 0xf6, 0x96, 0x3f, 0xae, 0x5b,
0x5f, 0x58, 0xe8, 0x3d, 0x14, 0x64, 0x93, 0x47, 0x19, 0x1d, 0x2b, 0x31, 0x21, 0xd8, 0xce, 0x32,
0x88, 0x39, 0xc5, 0x4f, 0x00, 0xb3, 0x51, 0x03, 0x65, 0xfc, 0x13, 0x32, 0x37, 0xb3, 0xd8, 0xf5,
0x9b, 0x81, 0xc6, 0xc1, 0x7b, 0xd9, 0x67, 0xcf, 0x18, 0xca, 0xec, 0xb0, 0xf1, 0x35, 0xb2, 0x9d,
0x65, 0x10, 0x63, 0xee, 0x1c, 0x6a, 0xa9, 0x7f, 0x4a, 0xd1, 0xcf, 0xb3, 0x83, 0xbc, 0xfe, 0xc7,
0xab, 0xfd, 0xea, 0x56, 0x58, 0xe3, 0x49, 0x24, 0x67, 0x35, 0xf3, 0x18, 0x35, 0x6e, 0x8a, 0x3b,
0xfd, 0xaf, 0xa7, 0xdd, 0xbc, 0x35, 0x5e, 0x7b, 0xdd, 0x2d, 0xfc, 0x36, 0x37, 0xee, 0x76, 0x8b,
0xea, 0x0f, 0xe4, 0xaf, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x18, 0x4b, 0xe5, 0x8f, 0xde, 0x16,
0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -192,6 +192,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

View File

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

View File

@@ -1,5 +1,5 @@
variable "GO_VERSION" {
default = "1.20"
default = null
}
variable "DOCS_FORMATS" {
default = "md"

View File

@@ -49,6 +49,16 @@ bin etc lib mnt proc run srv tmp var
dev home media opt root sbin sys usr work
```
Optional long form allows you specifying detailed configurations of the process.
It must be CSV-styled comma-separated key-value pairs.
Supported keys are `args` (can be JSON array format), `entrypoint` (can be JSON array format), `env` (can be JSON array format), `user`, `cwd` and `tty` (bool).
Example:
```
$ docker buildx build --invoke 'entrypoint=["sh"],"args=[""-c"", ""env | grep -e FOO -e AAA""]","env=[""FOO=bar"", ""AAA=bbb""]"' .
```
#### `on-error`
If you want to start a debug session when a build fails, you can use
@@ -106,12 +116,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
@@ -151,4 +161,4 @@ Attached to process "3ug8iqaufiwwnukimhqqt06jz". Press Ctrl-a-c to switch to the
bin etc lib mnt proc run srv tmp var
dev home media opt root sbin sys usr work
/ #
```
```

View File

@@ -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-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 |
| [`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

View File

@@ -23,11 +23,11 @@ Start a build
| [`--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] |
| `--invoke` | `string` | | Invoke a command after the build |
| `--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": {

View File

@@ -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
@@ -165,6 +165,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 +223,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)

View File

@@ -8,10 +8,10 @@ Start a monitor
| Name | Type | Default | Description |
|:------------------|:---------|:--------|:-----------------------------------------------------------------------------------------|
| `--builder` | `string` | | Override the configured builder instance |
| `--detach` | | | Detach buildx server (supported only on linux) [experimental] |
| `--detach` | | | Detach buildx server (supported only on linux) |
| `--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] |
| `--root` | `string` | | Specify root directory of server to connect |
| `--server-config` | `string` | | Specify buildx server config file (used only when launching new server) |
<!---MARKER_GEN_END-->

View File

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

View File

@@ -1,11 +0,0 @@
# buildx install
```
docker buildx install
```
<!---MARKER_GEN_START-->
Install buildx as a 'docker builder' alias
<!---MARKER_GEN_END-->

View File

@@ -1,11 +0,0 @@
# buildx uninstall
```
docker buildx uninstall
```
<!---MARKER_GEN_START-->
Uninstall the 'docker builder' alias
<!---MARKER_GEN_END-->

View File

@@ -8,6 +8,7 @@ import (
"os"
"path"
"path/filepath"
"strconv"
"strings"
"sync/atomic"
"time"
@@ -22,6 +23,7 @@ import (
"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"
@@ -40,6 +42,7 @@ type Driver struct {
netMode string
image string
cgroupParent string
securityOpts map[string]string
env []string
}
@@ -108,7 +111,6 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
if d.InitConfig.BuildkitFlags != nil {
cfg.Cmd = d.InitConfig.BuildkitFlags
}
useInit := true // let it cleanup exited processes created by BuildKit's container API
if err := l.Wrap("creating container "+d.Name, func() error {
hc := &container.HostConfig{
@@ -126,6 +128,13 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
hc.NetworkMode = container.NetworkMode(d.netMode)
}
if info, err := d.DockerAPI.Info(ctx); err == nil {
secOpts, err := dockertypes.DecodeSecurityOptions(info.SecurityOptions)
l.Wrap("driverOpts"+info.CgroupDriver, func() error {
return nil
})
if err != nil {
return err
}
if info.CgroupDriver == "cgroupfs" {
// Place all buildkit containers inside this cgroup by default so limits can be attached
// to all build activity on the host.
@@ -134,28 +143,39 @@ func (d *Driver) create(ctx context.Context, l progress.SubLogger) error {
hc.CgroupParent = d.cgroupParent
}
}
secOpts, err := dockertypes.DecodeSecurityOptions(info.SecurityOptions)
if err != nil {
return err
}
for _, f := range secOpts {
if f.Name == "userns" {
hc.UsernsMode = "host"
break
}
}
for i, k := range d.securityOpts {
switch {
case i == "systempaths":
hc.MaskedPaths = []string{}
hc.ReadonlyPaths = []string{}
case i == "privileged":
val, err := strconv.ParseBool(k)
if err != nil {
return errors.Errorf("invalid value privleged security option, options are true/false")
}
hc.Privileged = val
default:
hc.SecurityOpt = append(hc.SecurityOpt, i+"="+k)
}
}
}
_, 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 := d.start(ctx, l); 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.wait(ctx, l); err != nil {
return err
@@ -388,18 +408,11 @@ func (d *Driver) Factory() driver.Factory {
}
func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
var historyAPI bool
c, err := d.Client(ctx)
if err == nil {
historyAPI = driver.HistoryAPISupported(ctx, c)
c.Close()
}
return map[driver.Feature]bool{
driver.OCIExporter: true,
driver.DockerExporter: true,
driver.CacheExport: true,
driver.MultiPlatform: true,
driver.HistoryAPI: historyAPI,
}
}

View File

@@ -40,6 +40,7 @@ func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver
return nil, errors.Errorf("%s driver requires docker API access", f.Name())
}
d := &Driver{factory: f, InitConfig: cfg}
d.securityOpts = make(map[string]string)
for k, v := range cfg.DriverOpts {
switch {
case k == "network":
@@ -57,11 +58,32 @@ func (f *factory) New(ctx context.Context, cfg driver.InitConfig) (driver.Driver
return nil, errors.Errorf("invalid env option %q, expecting env.FOO=bar", k)
}
d.env = append(d.env, fmt.Sprintf("%s=%s", envName, v))
case k == "seccomp":
d.securityOpts[k] = v
case k == "apparmor":
d.securityOpts[k] = v
case k == "systempaths":
d.securityOpts[k] = v
case k == "privileged":
d.securityOpts[k] = v
default:
return nil, errors.Errorf("invalid driver option %s for docker-container driver", k)
}
}
for i, _ := range cfg.SecurityOpts {
switch {
case i == "seccomp":
continue
case i == "apparmor":
continue
case i == "systempaths":
continue
case i == "privileged":
continue
default:
return nil, errors.Errorf("invalid Security option %s for docker-container driver", i)
}
}
return d, nil
}

View File

@@ -60,7 +60,6 @@ func (d *Driver) Client(ctx context.Context) (*client.Client, error) {
func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
var useContainerdSnapshotter bool
var historyAPI bool
c, err := d.Client(ctx)
if err == nil {
workers, _ := c.ListWorkers(ctx)
@@ -69,7 +68,6 @@ func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
useContainerdSnapshotter = true
}
}
historyAPI = driver.HistoryAPISupported(ctx, c)
c.Close()
}
return map[driver.Feature]bool{
@@ -77,7 +75,6 @@ func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
driver.DockerExporter: useContainerdSnapshotter,
driver.CacheExport: useContainerdSnapshotter,
driver.MultiPlatform: useContainerdSnapshotter,
driver.HistoryAPI: historyAPI,
}
}

View File

@@ -64,7 +64,7 @@ type Driver interface {
Config() InitConfig
}
func Boot(ctx, clientContext context.Context, d Driver, pw progress.Writer) (*client.Client, error) {
func Boot(ctx, clientContext context.Context, d *DriverHandle, pw progress.Writer) (*client.Client, error) {
try := 0
for {
info, err := d.Info(ctx)
@@ -80,7 +80,6 @@ func Boot(ctx, clientContext context.Context, d Driver, pw progress.Writer) (*cl
return nil, err
}
}
c, err := d.Client(clientContext)
if err != nil {
if errors.Cause(err) == ErrNotRunning && try <= 2 {
@@ -92,7 +91,7 @@ func Boot(ctx, clientContext context.Context, d Driver, pw progress.Writer) (*cl
}
}
func HistoryAPISupported(ctx context.Context, c *client.Client) bool {
func historyAPISupported(ctx context.Context, c *client.Client) bool {
cl, err := c.ControlClient().ListenBuildHistory(ctx, &controlapi.BuildHistoryRequest{
ActiveOnly: true,
Ref: "buildx-test-history-api-feature", // dummy ref to check if the server supports the API

View File

@@ -7,5 +7,3 @@ const DockerExporter Feature = "Docker exporter"
const CacheExport Feature = "Cache export"
const MultiPlatform Feature = "Multiple platforms"
const HistoryAPI Feature = "History API"

View File

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

View File

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

View File

@@ -229,17 +229,10 @@ func (d *Driver) Factory() driver.Factory {
}
func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
var historyAPI bool
c, err := d.Client(ctx)
if err == nil {
historyAPI = driver.HistoryAPISupported(ctx, c)
c.Close()
}
return map[driver.Feature]bool{
driver.OCIExporter: true,
driver.DockerExporter: d.DockerAPI != nil,
driver.CacheExport: true,
driver.MultiPlatform: true, // Untested (needs multiple Driver instances)
driver.HistoryAPI: historyAPI,
}
}

View File

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

View File

@@ -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)
},
)

View File

@@ -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(),

View File

@@ -2,17 +2,17 @@ package driver
import (
"context"
"net"
"os"
"sort"
"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 {
@@ -56,6 +56,7 @@ type InitConfig struct {
BuildkitFlags []string
Files map[string][]byte
DriverOpts map[string]string
SecurityOpts map[string]string
Auth Auth
Platforms []specs.Platform
// ContextPathHash can be used for determining pods in the driver instance
@@ -104,7 +105,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) (Driver, 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, so map[string]string, platforms []specs.Platform, contextPathHash string) (*DriverHandle, error) {
ic := InitConfig{
EndpointAddr: endpointAddr,
DockerAPI: api,
@@ -112,6 +113,7 @@ func GetDriver(ctx context.Context, name string, f Factory, endpointAddr string,
Name: name,
BuildkitFlags: flags,
DriverOpts: do,
SecurityOpts: so,
Auth: auth,
Platforms: platforms,
ContextPathHash: contextPathHash,
@@ -128,7 +130,7 @@ func GetDriver(ctx context.Context, name string, f Factory, endpointAddr string,
if err != nil {
return nil, err
}
return &cachedDriver{Driver: d}, nil
return &DriverHandle{Driver: d}, nil
}
func GetFactories(instanceRequired bool) []Factory {
@@ -145,25 +147,72 @@ func GetFactories(instanceRequired bool) []Factory {
return ds
}
type cachedDriver struct {
type DriverHandle struct {
Driver
client *client.Client
err error
once sync.Once
featuresOnce sync.Once
features map[Feature]bool
client *client.Client
err error
once sync.Once
featuresOnce sync.Once
features map[Feature]bool
historyAPISupportedOnce sync.Once
historyAPISupported bool
hostGatewayIPOnce sync.Once
hostGatewayIP net.IP
hostGatewayIPErr error
}
func (d *cachedDriver) Client(ctx context.Context) (*client.Client, error) {
func (d *DriverHandle) Client(ctx context.Context) (*client.Client, error) {
d.once.Do(func() {
d.client, d.err = d.Driver.Client(ctx)
})
return d.client, d.err
}
func (d *cachedDriver) Features(ctx context.Context) map[Feature]bool {
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 {
d.historyAPISupported = historyAPISupported(ctx, c)
}
})
return d.historyAPISupported
}
func (d *DriverHandle) HostGatewayIP(ctx context.Context) (net.IP, error) {
d.hostGatewayIPOnce.Do(func() {
if !d.Driver.IsMobyDriver() {
d.hostGatewayIPErr = errors.New("host-gateway is only supported with the docker driver")
return
}
c, err := d.Client(ctx)
if err != nil {
d.hostGatewayIPErr = err
return
}
workers, err := c.ListWorkers(ctx)
if err != nil {
d.hostGatewayIPErr = errors.Wrap(err, "listing workers")
return
}
for _, w := range workers {
// 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.hostGatewayIPErr = errors.Errorf("failed to parse host-gateway IP: %s", v)
return
}
d.hostGatewayIP = ip
return
}
}
d.hostGatewayIPErr = errors.New("host-gateway IP not found")
})
return d.hostGatewayIP, d.hostGatewayIPErr
}

View File

@@ -7,6 +7,8 @@ import (
"github.com/docker/buildx/driver"
"github.com/docker/buildx/util/progress"
"github.com/moby/buildkit/client"
"google.golang.org/grpc"
"google.golang.org/grpc/backoff"
)
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,13 @@ 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{}
backoffConfig := backoff.DefaultConfig
backoffConfig.MaxDelay = 1 * time.Second
opts = append(opts, client.WithGRPCDialOption(
grpc.WithConnectParams(grpc.ConnectParams{Backoff: backoffConfig}),
))
if d.tlsOpts != nil {
opts = append(opts, []client.ClientOpt{
client.WithServerConfig(d.tlsOpts.serverName, d.tlsOpts.caCert),
@@ -88,18 +83,11 @@ func (d *Driver) Client(ctx context.Context) (*client.Client, error) {
}
func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool {
var historyAPI bool
c, err := d.Client(ctx)
if err == nil {
historyAPI = driver.HistoryAPISupported(ctx, c)
c.Close()
}
return map[driver.Feature]bool{
driver.OCIExporter: true,
driver.DockerExporter: true,
driver.CacheExport: true,
driver.MultiPlatform: true,
driver.HistoryAPI: historyAPI,
}
}

44
go.mod
View File

@@ -5,15 +5,16 @@ 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.17.0
github.com/containerd/console v1.0.3
github.com/containerd/containerd v1.7.1
github.com/containerd/containerd v1.7.2
github.com/containerd/continuity v0.4.1
github.com/containerd/typeurl/v2 v2.1.1
github.com/docker/cli v24.0.1+incompatible
github.com/docker/cli-docs-tool v0.5.1
github.com/creack/pty v1.1.18
github.com/docker/cli v24.0.5+incompatible
github.com/docker/cli-docs-tool v0.6.0
github.com/docker/distribution v2.8.2+incompatible
github.com/docker/docker v24.0.1+incompatible
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
@@ -22,7 +23,7 @@ require (
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.20230530080511-c36941f4a10e
github.com/moby/buildkit v0.12.1-0.20230804094609-b49a8873179b
github.com/moby/sys/mountinfo v0.6.2
github.com/moby/sys/signal v0.7.0
github.com/morikuni/aec v1.0.0
@@ -31,21 +32,22 @@ require (
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
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.8.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 (
@@ -103,7 +105,7 @@ require (
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/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
@@ -138,10 +140,10 @@ require (
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/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
@@ -155,11 +157,11 @@ require (
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/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
golang.org/x/net v0.10.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.8.0 // indirect
golang.org/x/text v0.9.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

89
go.sum
View File

@@ -122,13 +122,13 @@ 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.17.0 h1:cvje90CU94dQyTnJoHJYjx9yE4Iggse1XmGcO3Qi5ts=
github.com/compose-spec/compose-go v1.17.0/go.mod h1:zR2tP1+kZHi5vJz7PjpW6oMoDji/Js3GHjP+hfjf70Q=
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.1 h1:k8DbDkSOwt5rgxQ3uCI4WMKIJxIndSCBUaGm5oRn+Go=
github.com/containerd/containerd v1.7.1/go.mod h1:gA+nJUADRBm98QS5j5RPROnt0POQSMK+r7P7EGMC/Qc=
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/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
@@ -142,6 +142,7 @@ 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/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -149,14 +150,14 @@ 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.1+incompatible h1:uVl5Xv/39kZJpDo9VaktTOYBc702sdYYF33FqwUG/dM=
github.com/docker/cli v24.0.1+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/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.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.1+incompatible h1:NxN81beIxDlUaVt46iUQrYHD9/W3u9EGl52r86O/IGw=
github.com/docker/docker v24.0.1+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=
@@ -315,8 +316,8 @@ 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/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.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -371,8 +372,8 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzC
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
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.20230530080511-c36941f4a10e h1:d5nOEUewXcVebVTyUVeQHXX8+Ofb/+TSlqZSn9xIg3k=
github.com/moby/buildkit v0.11.0-rc3.0.20230530080511-c36941f4a10e/go.mod h1:nWISTd0U2LNfp6z0W5T0NO73xO5rrdRiTTQkSF6uIjc=
github.com/moby/buildkit v0.12.1-0.20230804094609-b49a8873179b h1:LUpEbvxcyM0NuWk54WwNjDVZ5YujyCm1CudzZpqaohE=
github.com/moby/buildkit v0.12.1-0.20230804094609-b49a8873179b/go.mod h1:bs0LeDdh7AQpYXLiPNUt+hzDjRxMg+QeLq1a1r0awFM=
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=
@@ -411,7 +412,6 @@ github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh
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/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 h1:DiLBVp4DAcZlBVBEtJpNWZpZVq0AEeCY7Hqk8URVs4o=
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=
@@ -457,10 +457,10 @@ github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.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.0 h1:/fqihV2Jna7fmow65dHpgKNsilgLK7ICpd2tkCnPEyY=
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/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
@@ -485,18 +485,19 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
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/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=
@@ -564,6 +565,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=
@@ -584,8 +587,8 @@ 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=
@@ -617,8 +620,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.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
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=
@@ -637,8 +640,8 @@ 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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -680,19 +683,19 @@ 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.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
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=
@@ -873,14 +876,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=

View File

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

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.20
ARG GO_VERSION=1.20.7
ARG FORMATS=md,yaml
FROM golang:${GO_VERSION}-alpine AS docsgen

View File

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

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.20
ARG GO_VERSION=1.20.7
FROM golang:${GO_VERSION}-alpine
RUN apk add --no-cache git gcc musl-dev

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.20
ARG GO_VERSION=1.20.7
ARG MODOUTDATED_VERSION=v0.8.0
FROM golang:${GO_VERSION}-alpine AS base

View File

@@ -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.
`,
}
}

View File

@@ -41,6 +41,7 @@ func (cm *ExecCmd) Exec(ctx context.Context, args []string) error {
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,

View File

@@ -47,6 +47,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)

View File

@@ -282,6 +282,8 @@ 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

BIN
out/buildx Executable file

Binary file not shown.

View File

@@ -24,11 +24,12 @@ type NodeGroup struct {
}
type Node struct {
Name string
Endpoint string
Platforms []specs.Platform
Flags []string
DriverOpts map[string]string
Name string
Endpoint string
Platforms []specs.Platform
Flags []string
DriverOpts map[string]string
SecurityOpts map[string]string
Files map[string][]byte
}
@@ -48,7 +49,7 @@ func (ng *NodeGroup) Leave(name string) error {
return nil
}
func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpointsSet bool, actionAppend bool, flags []string, configFile string, do map[string]string) error {
func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpointsSet bool, actionAppend bool, flags []string, configFile string, do map[string]string, so map[string]string) error {
if ng.Dynamic {
return errors.New("dynamic node group does not support Update")
}
@@ -91,6 +92,10 @@ func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpoints
n.DriverOpts = do
needsRestart = true
}
if so != nil {
n.SecurityOpts = so
needsRestart = true
}
if configFile != "" {
for k, v := range files {
n.Files[k] = v
@@ -118,12 +123,13 @@ func (ng *NodeGroup) Update(name, endpoint string, platforms []string, endpoints
}
n := Node{
Name: name,
Endpoint: endpoint,
Platforms: pp,
Flags: flags,
DriverOpts: do,
Files: files,
Name: name,
Endpoint: endpoint,
Platforms: pp,
Flags: flags,
DriverOpts: do,
SecurityOpts: so,
Files: files,
}
ng.Nodes = append(ng.Nodes, n)
@@ -156,6 +162,10 @@ func (n *Node) Copy() *Node {
for k, v := range n.DriverOpts {
driverOpts[k] = v
}
securityOpts := map[string]string{}
for k, v := range n.SecurityOpts {
securityOpts[k] = v
}
files := map[string][]byte{}
for k, v := range n.Files {
vv := []byte{}
@@ -163,12 +173,13 @@ func (n *Node) Copy() *Node {
files[k] = vv
}
return &Node{
Name: n.Name,
Endpoint: n.Endpoint,
Platforms: platforms,
Flags: flags,
DriverOpts: driverOpts,
Files: files,
Name: n.Name,
Endpoint: n.Endpoint,
Platforms: platforms,
Flags: flags,
DriverOpts: driverOpts,
SecurityOpts: securityOpts,
Files: files,
}
}

View File

@@ -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))
}

View File

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

View File

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

View File

@@ -18,6 +18,7 @@ func bakeCmd(sb integration.Sandbox, opts ...cmdOpt) (string, error) {
}
var bakeTests = []func(t *testing.T, sb integration.Sandbox){
testBakeLocal,
testBakeRemote,
testBakeRemoteCmdContext,
testBakeRemoteCmdContextOverride,
@@ -26,6 +27,29 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
testBakeRemoteCmdContextEscapeRelative,
}
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()
out, err := bakeCmd(sb, withDir(dir), withArgs("--set", "*.output=type=local,dest="+dirDest))
require.NoError(t, err, out)
require.FileExists(t, filepath.Join(dirDest, "foo"))
}
func testBakeRemote(t *testing.T, sb integration.Sandbox) {
bakefile := []byte(`
target "default" {

View File

@@ -3,19 +3,23 @@ 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/require"
)
@@ -31,7 +35,11 @@ var buildTests = []func(t *testing.T, sb integration.Sandbox){
testImageIDOutput,
testBuildLocalExport,
testBuildRegistryExport,
testBuildRegistryExportAttestations,
testBuildTarExport,
testBuildMobyFromLocalImage,
testBuildDetailsLink,
testBuildProgress,
}
func testBuild(t *testing.T, sb integration.Sandbox) {
@@ -89,6 +97,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 +141,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 +181,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 +287,29 @@ 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")
}

267
tests/imagetools.go Normal file
View 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
}

View File

@@ -33,6 +33,8 @@ func testInspect(t *testing.T, sb integration.Sandbox) {
driver = 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)
}

View File

@@ -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"
}

View File

@@ -7,10 +7,11 @@ import (
"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 {

View File

@@ -23,9 +23,10 @@ func testLs(t *testing.T, sb integration.Sandbox) {
out, err := lsCmd(sb)
require.NoError(t, err, string(out))
sbDriver, _, _ := strings.Cut(sb.Name(), "+")
for _, line := range strings.Split(out, "\n") {
if strings.Contains(line, sb.Address()) {
require.Contains(t, line, sb.Name())
require.Contains(t, line, sbDriver)
return
}
}

55
tests/version.go Normal file
View File

@@ -0,0 +1,55 @@
package tests
import (
"strings"
"testing"
"github.com/moby/buildkit/util/testutil/integration"
"github.com/stretchr/testify/require"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
)
var versionTests = []func(t *testing.T, sb integration.Sandbox){
testVersion,
}
func testVersion(t *testing.T, sb integration.Sandbox) {
cmd := buildxCmd(sb, withArgs("version"))
out, err := cmd.CombinedOutput()
require.NoError(t, err, string(out))
// There should be at least one newline and the first line
// of output should contain the name, version, and possibly a revision.
firstLine, _, hasNewline := strings.Cut(string(out), "\n")
require.True(t, hasNewline, "At least one newline is required in the output")
// Log the output to make debugging easier.
t.Log(firstLine)
// Split by spaces into at least 2 fields.
fields := strings.Fields(firstLine)
require.GreaterOrEqual(t, len(fields), 2, "Expected at least 2 fields in the first line")
// First field should be an import path.
// This can be any valid import path for Go
// so don't set too many restrictions here.
// Just checking if the import path is a valid Go
// path should be suitable enough to make sure this is ok.
// Using CheckImportPath instead of CheckPath as it is less
// restrictive.
importPath := fields[0]
require.NoError(t, module.CheckImportPath(importPath), "First field was not a valid import path: %+v", importPath)
// Second field should be a version.
// This defaults to something that's still compatible
// with semver.
version := fields[1]
require.True(t, semver.IsValid(version), "Second field was not valid semver: %+v", version)
// Revision should be empty or should look like a git hash.
if len(fields) > 2 && len(fields[2]) > 0 {
revision := fields[2]
require.Regexp(t, `[0-9a-f]{40}`, revision, "Third field was not a git revision: %+v", revision)
}
}

View File

@@ -1,10 +1,20 @@
package workers
import (
"os"
"strings"
"github.com/moby/buildkit/util/testutil/integration"
)
type backend struct {
builder string
context string
builder string
context string
unsupportedFeatures []string
}
var _ integration.Backend = &backend{}
func (s *backend) Address() string {
return s.builder
}
@@ -24,3 +34,26 @@ func (s *backend) Snapshotter() string {
func (s *backend) Rootless() bool {
return false
}
func (s backend) Supports(feature string) bool {
if enabledFeatures := os.Getenv("BUILDKIT_TEST_ENABLE_FEATURES"); enabledFeatures != "" {
for _, enabledFeature := range strings.Split(enabledFeatures, ",") {
if feature == enabledFeature {
return true
}
}
}
if disabledFeatures := os.Getenv("BUILDKIT_TEST_DISABLE_FEATURES"); disabledFeatures != "" {
for _, disabledFeature := range strings.Split(disabledFeatures, ",") {
if feature == disabledFeature {
return false
}
}
}
for _, unsupportedFeature := range s.unsupportedFeatures {
if feature == unsupportedFeature {
return false
}
}
return true
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"os"
"os/exec"
"sync"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/util/testutil/integration"
@@ -18,6 +19,13 @@ func InitDockerContainerWorker() {
type containerWorker struct {
id string
unsupported []string
docker integration.Backend
dockerClose func() error
dockerErr error
dockerOnce sync.Once
}
func (w *containerWorker) Name() string {
@@ -29,9 +37,11 @@ func (w *containerWorker) Rootless() bool {
}
func (w *containerWorker) New(ctx context.Context, cfg *integration.BackendConfig) (integration.Backend, func() error, error) {
bk, bkclose, err := dockerWorker{id: w.id}.New(ctx, cfg)
if err != nil {
return bk, bkclose, err
w.dockerOnce.Do(func() {
w.docker, w.dockerClose, w.dockerErr = dockerWorker{id: w.id}.New(ctx, cfg)
})
if w.dockerErr != nil {
return w.docker, w.dockerClose, w.dockerErr
}
name := "integration-container-" + identity.NewID()
@@ -42,25 +52,37 @@ func (w *containerWorker) New(ctx context.Context, cfg *integration.BackendConfi
"--driver=docker-container",
"--driver-opt=network=host",
)
cmd.Env = append(os.Environ(), "DOCKER_CONTEXT="+bk.DockerAddress())
cmd.Env = append(
os.Environ(),
"BUILDX_CONFIG=/tmp/buildx-"+name,
"DOCKER_CONTEXT="+w.docker.DockerAddress(),
)
if err := cmd.Run(); err != nil {
return nil, nil, errors.Wrapf(err, "failed to create buildx instance %s", name)
}
cl := func() error {
var err error
if err1 := bkclose(); err == nil {
err = err1
}
cmd := exec.Command("buildx", "rm", "-f", name)
if err1 := cmd.Run(); err == nil {
err = err1
}
return err
return cmd.Run()
}
return &backend{
context: bk.DockerAddress(),
builder: name,
context: w.docker.DockerAddress(),
builder: name,
unsupportedFeatures: w.unsupported,
}, cl, nil
}
func (w *containerWorker) Close() error {
if close := w.dockerClose; close != nil {
return close()
}
// reset the worker to be ready to go again
w.docker = nil
w.dockerClose = nil
w.dockerErr = nil
w.dockerOnce = sync.Once{}
return nil
}

View File

@@ -2,10 +2,12 @@ package workers
import (
"context"
"os"
"os/exec"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/util/testutil/integration"
bkworkers "github.com/moby/buildkit/util/testutil/workers"
"github.com/pkg/errors"
)
@@ -13,10 +15,16 @@ func InitDockerWorker() {
integration.Register(&dockerWorker{
id: "docker",
})
integration.Register(&dockerWorker{
id: "docker+containerd",
containerdSnapshotter: true,
})
}
type dockerWorker struct {
id string
id string
containerdSnapshotter bool
unsupported []string
}
func (c dockerWorker) Name() string {
@@ -28,8 +36,9 @@ func (c dockerWorker) Rootless() bool {
}
func (c dockerWorker) New(ctx context.Context, cfg *integration.BackendConfig) (b integration.Backend, cl func() error, err error) {
moby := integration.Moby{
ID: c.id,
moby := bkworkers.Moby{
ID: c.id,
ContainerdSnapshotter: c.containerdSnapshotter,
}
bk, bkclose, err := moby.New(ctx, cfg)
if err != nil {
@@ -41,8 +50,9 @@ func (c dockerWorker) New(ctx context.Context, cfg *integration.BackendConfig) (
name,
"--docker", "host="+bk.DockerAddress(),
)
cmd.Env = append(os.Environ(), "BUILDX_CONFIG=/tmp/buildx-"+name)
if err := cmd.Run(); err != nil {
return nil, cl, errors.Wrapf(err, "failed to create buildx instance %s", name)
return bk, cl, errors.Wrapf(err, "failed to create buildx instance %s", name)
}
cl = func() error {
@@ -58,7 +68,12 @@ func (c dockerWorker) New(ctx context.Context, cfg *integration.BackendConfig) (
}
return &backend{
builder: name,
context: name,
builder: name,
context: name,
unsupportedFeatures: c.unsupported,
}, cl, nil
}
func (c dockerWorker) Close() error {
return nil
}

13
tests/workers/features.go Normal file
View File

@@ -0,0 +1,13 @@
package workers
import (
"testing"
"github.com/moby/buildkit/util/testutil/integration"
)
var features = map[string]struct{}{}
func CheckFeatureCompat(t *testing.T, sb integration.Sandbox, reason ...string) {
integration.CheckFeatureCompat(t, sb, features, reason...)
}

View File

@@ -2,10 +2,12 @@ package workers
import (
"context"
"os"
"os/exec"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/util/testutil/integration"
bkworkers "github.com/moby/buildkit/util/testutil/workers"
"github.com/pkg/errors"
)
@@ -16,7 +18,8 @@ func InitRemoteWorker() {
}
type remoteWorker struct {
id string
id string
unsupported []string
}
func (w remoteWorker) Name() string {
@@ -28,7 +31,7 @@ func (w remoteWorker) Rootless() bool {
}
func (w remoteWorker) New(ctx context.Context, cfg *integration.BackendConfig) (b integration.Backend, cl func() error, err error) {
oci := integration.OCI{ID: w.id}
oci := bkworkers.OCI{ID: w.id}
bk, bkclose, err := oci.New(ctx, cfg)
if err != nil {
return bk, cl, err
@@ -41,6 +44,7 @@ func (w remoteWorker) New(ctx context.Context, cfg *integration.BackendConfig) (
"--driver=remote",
bk.Address(),
)
cmd.Env = append(os.Environ(), "BUILDX_CONFIG=/tmp/buildx-"+name)
if err := cmd.Run(); err != nil {
return nil, nil, errors.Wrapf(err, "failed to create buildx instance %s", name)
}
@@ -58,6 +62,11 @@ func (w remoteWorker) New(ctx context.Context, cfg *integration.BackendConfig) (
}
return &backend{
builder: name,
builder: name,
unsupportedFeatures: w.unsupported,
}, cl, nil
}
func (w remoteWorker) Close() error {
return nil
}

View File

@@ -1,21 +1,15 @@
package buildflags
import (
"github.com/moby/buildkit/util/entitlements"
"github.com/pkg/errors"
)
import "github.com/moby/buildkit/util/entitlements"
func ParseEntitlements(in []string) ([]entitlements.Entitlement, error) {
out := make([]entitlements.Entitlement, 0, len(in))
for _, v := range in {
switch v {
case "security.insecure":
out = append(out, entitlements.EntitlementSecurityInsecure)
case "network.host":
out = append(out, entitlements.EntitlementNetworkHost)
default:
return nil, errors.Errorf("invalid entitlement: %v", v)
e, err := entitlements.Parse(v)
if err != nil {
return nil, err
}
out = append(out, e)
}
return out, nil
}

View File

@@ -19,7 +19,7 @@ func Disable(cmd *cobra.Command, args []string, toComplete string) ([]string, co
func BakeTargets(files []string) ValidArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
f, err := bake.ReadLocalFiles(files)
f, err := bake.ReadLocalFiles(files, nil)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}

View File

@@ -81,6 +81,6 @@ func (e *ErrorWithBuildRef) Print(w io.Writer) error {
if _, err := console.ConsoleFromFile(os.Stderr); err == nil {
term = true
}
fmt.Fprintf(w, "\n%s", BuildDetailsOutput(map[string]string{"default": e.Ref}, term))
fmt.Fprintf(w, "\n%s\n", BuildDetailsOutput(map[string]string{"default": e.Ref}, term))
return nil
}

View File

@@ -13,6 +13,9 @@ import (
// Client represents an active docker object.
type Client struct {
cli command.Cli
featuresOnce sync.Once
featuresCache map[Feature]bool
}
// NewClient initializes a new docker client.
@@ -43,17 +46,24 @@ func (c *Client) LoadImage(ctx context.Context, name string, status progress.Wri
w = &waitingWriter{
PipeWriter: pw,
f: func() {
resp, err := dapi.ImageLoad(ctx, pr, false)
defer close(done)
if err != nil {
handleErr := func(err error) {
pr.CloseWithError(err)
w.mu.Lock()
w.err = err
w.mu.Unlock()
}
resp, err := dapi.ImageLoad(ctx, pr, false)
defer close(done)
if err != nil {
handleErr(err)
return
}
prog := progress.WithPrefix(status, "", false)
progress.FromReader(prog, "importing to docker", resp.Body)
if err := fromReader(prog, "importing to docker", resp.Body); err != nil {
handleErr(err)
}
},
done: done,
cancel: cancel,
@@ -64,6 +74,13 @@ func (c *Client) LoadImage(ctx context.Context, name string, status progress.Wri
}
func (c *Client) Features(ctx context.Context, name string) map[Feature]bool {
c.featuresOnce.Do(func() {
c.featuresCache = c.features(ctx, name)
})
return c.featuresCache
}
func (c *Client) features(ctx context.Context, name string) map[Feature]bool {
features := make(map[Feature]bool)
if dapi, err := c.API(name); err == nil {
if info, err := dapi.Info(ctx); err == nil {

View File

@@ -1,15 +1,19 @@
package progress
package dockerutil
import (
"errors"
"io"
"time"
"github.com/docker/buildx/util/progress"
"github.com/docker/cli/cli/streams"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/identity"
"github.com/opencontainers/go-digest"
)
func FromReader(w Writer, name string, rc io.ReadCloser) {
func fromReader(w progress.Writer, name string, rc io.ReadCloser) error {
dgst := digest.FromBytes([]byte(identity.NewID()))
tm := time.Now()
@@ -23,7 +27,12 @@ func FromReader(w Writer, name string, rc io.ReadCloser) {
Vertexes: []*client.Vertex{&vtx},
})
_, err := io.Copy(io.Discard, rc)
err := jsonmessage.DisplayJSONMessagesToStream(rc, streams.NewOut(io.Discard), nil)
if err != nil {
if jerr, ok := err.(*jsonmessage.JSONError); ok {
err = errors.New(jerr.Message)
}
}
tm2 := time.Now()
vtx2 := vtx
@@ -34,4 +43,5 @@ func FromReader(w Writer, name string, rc io.ReadCloser) {
w.Write(&client.SolveStatus{
Vertexes: []*client.Vertex{&vtx2},
})
return err
}

View File

@@ -49,7 +49,7 @@ func New(opts ...Option) (*Git, error) {
c.gitpath, err = gitPath(c.wd)
if err != nil {
return nil, errors.New("git not found in PATH")
return nil, err
}
return c, nil

View File

@@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"net/url"
"regexp"
"strings"
"github.com/containerd/containerd/content"
@@ -13,6 +14,7 @@ import (
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/remotes"
"github.com/docker/distribution/reference"
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/util/contentutil"
"github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go"
@@ -26,7 +28,7 @@ type Source struct {
Ref reference.Named
}
func (r *Resolver) Combine(ctx context.Context, srcs []*Source) ([]byte, ocispec.Descriptor, error) {
func (r *Resolver) Combine(ctx context.Context, srcs []*Source, ann map[string]string) ([]byte, ocispec.Descriptor, error) {
eg, ctx := errgroup.WithContext(ctx)
dts := make([][]byte, len(srcs))
@@ -75,7 +77,7 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source) ([]byte, ocispec
}
// on single source, return original bytes
if len(srcs) == 1 {
if len(srcs) == 1 && len(ann) == 0 {
if mt := srcs[0].Desc.MediaType; mt == images.MediaTypeDockerSchema2ManifestList || mt == ocispec.MediaTypeImageIndex {
return dts[0], srcs[0].Desc, nil
}
@@ -138,12 +140,39 @@ func (r *Resolver) Combine(ctx context.Context, srcs []*Source) ([]byte, ocispec
mt = ocispec.MediaTypeImageIndex
}
// annotations are only allowed on OCI indexes
indexAnnotation := make(map[string]string)
if mt == ocispec.MediaTypeImageIndex {
annotations, err := parseAnnotations(ann)
if err != nil {
return nil, ocispec.Descriptor{}, err
}
if len(annotations[exptypes.AnnotationIndex]) > 0 {
for k, v := range annotations[exptypes.AnnotationIndex] {
indexAnnotation[k.Key] = v
}
}
if len(annotations[exptypes.AnnotationManifestDescriptor]) > 0 {
for i := 0; i < len(newDescs); i++ {
if newDescs[i].Annotations == nil {
newDescs[i].Annotations = map[string]string{}
}
for k, v := range annotations[exptypes.AnnotationManifestDescriptor] {
if k.Platform == nil || k.PlatformString() == platforms.Format(*newDescs[i].Platform) {
newDescs[i].Annotations[k.Key] = v
}
}
}
}
}
idxBytes, err := json.MarshalIndent(ocispec.Index{
MediaType: mt,
Versioned: specs.Versioned{
SchemaVersion: 2,
},
Manifests: newDescs,
Manifests: newDescs,
Annotations: indexAnnotation,
}, "", " ")
if err != nil {
return nil, ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal index")
@@ -266,3 +295,52 @@ func detectMediaType(dt []byte) (string, error) {
return images.MediaTypeDockerSchema2ManifestList, nil
}
func parseAnnotations(ann map[string]string) (map[string]map[exptypes.AnnotationKey]string, error) {
// TODO: use buildkit's annotation parser once it supports setting custom prefix and ":" separator
annotationRegexp := regexp.MustCompile(`^([a-z-]+)(?:\[([A-Za-z0-9_/-]+)\])?:(\S+)$`)
indexAnnotations := make(map[exptypes.AnnotationKey]string)
manifestDescriptorAnnotations := make(map[exptypes.AnnotationKey]string)
for k, v := range ann {
groups := annotationRegexp.FindStringSubmatch(k)
if groups == nil {
return nil, errors.Errorf("invalid annotation format, expected <type>:<key>=<value>, got %q", k)
}
typ, platform, key := groups[1], groups[2], groups[3]
var ociPlatform *ocispec.Platform
if platform != "" {
p, err := platforms.Parse(platform)
if err != nil {
return nil, errors.Wrapf(err, "invalid platform %q", platform)
}
ociPlatform = &p
}
switch typ {
case exptypes.AnnotationIndex:
ak := exptypes.AnnotationKey{
Type: typ,
Platform: ociPlatform,
Key: key,
}
indexAnnotations[ak] = v
case exptypes.AnnotationManifestDescriptor:
ak := exptypes.AnnotationKey{
Type: typ,
Platform: ociPlatform,
Key: key,
}
manifestDescriptorAnnotations[ak] = v
case exptypes.AnnotationManifest:
return nil, errors.Errorf("%q annotations are not supported yet", typ)
case exptypes.AnnotationIndexDescriptor:
return nil, errors.Errorf("%q annotations are invalid while creating an image", typ)
default:
return nil, errors.Errorf("unknown annotation type %q", typ)
}
}
return map[string]map[exptypes.AnnotationKey]string{
exptypes.AnnotationIndex: indexAnnotations,
exptypes.AnnotationManifestDescriptor: manifestDescriptorAnnotations,
}, nil
}

View File

@@ -15,9 +15,7 @@ import (
clitypes "github.com/docker/cli/cli/config/types"
"github.com/docker/distribution/reference"
"github.com/moby/buildkit/util/contentutil"
"github.com/moby/buildkit/util/imageutil"
"github.com/moby/buildkit/util/tracing"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus"
)
@@ -162,11 +160,3 @@ func RegistryAuthForRef(ref string, a Auth) (string, error) {
}
return base64.URLEncoding.EncodeToString(buf), nil
}
func (r *Resolver) ImageConfig(ctx context.Context, in string, platform *ocispec.Platform) (digest.Digest, []byte, error) {
in, _, err := r.Resolve(ctx, in)
if err != nil {
return "", nil, err
}
return imageutil.Config(ctx, in, r.resolver(), r.buffer, nil, platform)
}

View File

@@ -20,7 +20,9 @@ func (w *pw) Write(st *client.SolveStatus) {
}
}
if w.diff != nil {
vertexes := make([]*client.Vertex, 0, len(st.Vertexes))
for _, v := range st.Vertexes {
v := *v
if v.Started != nil {
d := v.Started.Add(-*w.diff)
v.Started = &d
@@ -29,8 +31,12 @@ func (w *pw) Write(st *client.SolveStatus) {
d := v.Completed.Add(-*w.diff)
v.Completed = &d
}
vertexes = append(vertexes, &v)
}
statuses := make([]*client.VertexStatus, 0, len(st.Statuses))
for _, v := range st.Statuses {
v := *v
if v.Started != nil {
d := v.Started.Add(-*w.diff)
v.Started = &d
@@ -40,9 +46,21 @@ func (w *pw) Write(st *client.SolveStatus) {
v.Completed = &d
}
v.Timestamp = v.Timestamp.Add(-*w.diff)
statuses = append(statuses, &v)
}
logs := make([]*client.VertexLog, 0, len(st.Logs))
for _, v := range st.Logs {
v := *v
v.Timestamp = v.Timestamp.Add(-*w.diff)
logs = append(logs, &v)
}
st = &client.SolveStatus{
Vertexes: vertexes,
Statuses: statuses,
Logs: logs,
Warnings: st.Warnings,
}
}
w.Writer.Write(st)

View File

@@ -17,7 +17,6 @@
package cli
import (
"bytes"
"io"
"os"
"path/filepath"
@@ -250,7 +249,7 @@ func WithDotEnv(o *ProjectOptions) error {
if err != nil {
return err
}
envMap, err := GetEnvFromFile(o.Environment, wd, o.EnvFiles)
envMap, err := dotenv.GetEnvFromFile(o.Environment, wd, o.EnvFiles)
if err != nil {
return err
}
@@ -262,65 +261,6 @@ func WithDotEnv(o *ProjectOptions) error {
return nil
}
func GetEnvFromFile(currentEnv map[string]string, workingDir string, filenames []string) (map[string]string, error) {
envMap := make(map[string]string)
dotEnvFiles := filenames
if len(dotEnvFiles) == 0 {
dotEnvFiles = append(dotEnvFiles, filepath.Join(workingDir, ".env"))
}
for _, dotEnvFile := range dotEnvFiles {
abs, err := filepath.Abs(dotEnvFile)
if err != nil {
return envMap, err
}
dotEnvFile = abs
s, err := os.Stat(dotEnvFile)
if os.IsNotExist(err) {
if len(filenames) == 0 {
return envMap, nil
}
return envMap, errors.Errorf("Couldn't find env file: %s", dotEnvFile)
}
if err != nil {
return envMap, err
}
if s.IsDir() {
if len(filenames) == 0 {
return envMap, nil
}
return envMap, errors.Errorf("%s is a directory", dotEnvFile)
}
b, err := os.ReadFile(dotEnvFile)
if os.IsNotExist(err) {
return nil, errors.Errorf("Couldn't read env file: %s", dotEnvFile)
}
if err != nil {
return envMap, err
}
env, err := dotenv.ParseWithLookup(bytes.NewReader(b), func(k string) (string, bool) {
v, ok := currentEnv[k]
if ok {
return v, true
}
v, ok = envMap[k]
return v, ok
})
if err != nil {
return envMap, errors.Wrapf(err, "failed to read %s", dotEnvFile)
}
for k, v := range env {
envMap[k] = v
}
}
return envMap, nil
}
// WithInterpolation set ProjectOptions to enable/skip interpolation
func WithInterpolation(interpolation bool) ProjectOptionsFn {
return func(o *ProjectOptions) error {

View File

@@ -0,0 +1,84 @@
/*
Copyright 2020 The Compose Specification Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dotenv
import (
"bytes"
"os"
"path/filepath"
"github.com/pkg/errors"
)
func GetEnvFromFile(currentEnv map[string]string, workingDir string, filenames []string) (map[string]string, error) {
envMap := make(map[string]string)
dotEnvFiles := filenames
if len(dotEnvFiles) == 0 {
dotEnvFiles = append(dotEnvFiles, filepath.Join(workingDir, ".env"))
}
for _, dotEnvFile := range dotEnvFiles {
abs, err := filepath.Abs(dotEnvFile)
if err != nil {
return envMap, err
}
dotEnvFile = abs
s, err := os.Stat(dotEnvFile)
if os.IsNotExist(err) {
if len(filenames) == 0 {
return envMap, nil
}
return envMap, errors.Errorf("Couldn't find env file: %s", dotEnvFile)
}
if err != nil {
return envMap, err
}
if s.IsDir() {
if len(filenames) == 0 {
return envMap, nil
}
return envMap, errors.Errorf("%s is a directory", dotEnvFile)
}
b, err := os.ReadFile(dotEnvFile)
if os.IsNotExist(err) {
return nil, errors.Errorf("Couldn't read env file: %s", dotEnvFile)
}
if err != nil {
return envMap, err
}
env, err := ParseWithLookup(bytes.NewReader(b), func(k string) (string, bool) {
v, ok := currentEnv[k]
if ok {
return v, true
}
v, ok = envMap[k]
return v, ok
})
if err != nil {
return envMap, errors.Wrapf(err, "failed to read %s", dotEnvFile)
}
for k, v := range env {
envMap[k] = v
}
}
return envMap, nil
}

View File

@@ -123,8 +123,8 @@ loop:
}
return "", "", inherited, fmt.Errorf(
`line %d: unexpected character %q in variable name`,
p.line, string(rune))
`line %d: unexpected character %q in variable name %q`,
p.line, string(rune), strings.Split(src, "\n")[0])
}
}
@@ -153,17 +153,24 @@ func (p *parser) extractVarValue(src string, envMap map[string]string, lookupFn
return retVal, rest, err
}
previousCharIsEscape := false
// lookup quoted string terminator
for i := 1; i < len(src); i++ {
if src[i] == '\n' {
p.line++
}
if char := src[i]; char != quote {
if !previousCharIsEscape && char == '\\' {
previousCharIsEscape = true
} else {
previousCharIsEscape = false
}
continue
}
// skip escaped quote symbol (\" or \', depends on quote)
if prevChar := src[i-1]; prevChar == '\\' {
if previousCharIsEscape {
previousCharIsEscape = false
continue
}

View File

@@ -24,7 +24,7 @@ services:
- bar
labels: [FOO=BAR]
additional_contexts:
foo: /bar
foo: ./bar
secrets:
- secret1
- source: secret2
@@ -181,6 +181,7 @@ services:
timeout: 1s
retries: 5
start_period: 15s
start_interval: 5s
# Any valid image reference - repo, tag, id, sha
image: redis

View File

@@ -0,0 +1,120 @@
/*
Copyright 2020 The Compose Specification Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package loader
import (
"fmt"
"path/filepath"
"github.com/compose-spec/compose-go/dotenv"
"github.com/compose-spec/compose-go/types"
"github.com/pkg/errors"
)
// LoadIncludeConfig parse the require config from raw yaml
func LoadIncludeConfig(source []interface{}) ([]types.IncludeConfig, error) {
var requires []types.IncludeConfig
err := Transform(source, &requires)
return requires, err
}
var transformIncludeConfig TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case string:
return map[string]interface{}{"path": value}, nil
case map[string]interface{}:
return value, nil
default:
return data, errors.Errorf("invalid type %T for `include` configuration", value)
}
}
func loadInclude(configDetails types.ConfigDetails, model *types.Config, options *Options, loaded []string) (*types.Config, error) {
for _, r := range model.Include {
for i, p := range r.Path {
if !filepath.IsAbs(p) {
r.Path[i] = filepath.Join(configDetails.WorkingDir, p)
}
}
if r.ProjectDirectory == "" {
r.ProjectDirectory = filepath.Dir(r.Path[0])
}
loadOptions := options.clone()
loadOptions.SetProjectName(model.Name, true)
loadOptions.ResolvePaths = true
loadOptions.SkipNormalization = true
loadOptions.SkipConsistencyCheck = true
env, err := dotenv.GetEnvFromFile(configDetails.Environment, r.ProjectDirectory, r.EnvFile)
if err != nil {
return nil, err
}
imported, err := load(types.ConfigDetails{
WorkingDir: r.ProjectDirectory,
ConfigFiles: types.ToConfigFiles(r.Path),
Environment: env,
}, loadOptions, loaded)
if err != nil {
return nil, err
}
err = importResources(model, imported, r.Path)
if err != nil {
return nil, err
}
}
model.Include = nil
return model, nil
}
// importResources import into model all resources defined by imported, and report error on conflict
func importResources(model *types.Config, imported *types.Project, path []string) error {
services := mapByName(model.Services)
for _, service := range imported.Services {
if _, ok := services[service.Name]; ok {
return fmt.Errorf("imported compose file %s defines conflicting service %s", path, service.Name)
}
model.Services = append(model.Services, service)
}
for n, network := range imported.Networks {
if _, ok := model.Networks[n]; ok {
return fmt.Errorf("imported compose file %s defines conflicting network %s", path, n)
}
model.Networks[n] = network
}
for n, volume := range imported.Volumes {
if _, ok := model.Volumes[n]; ok {
return fmt.Errorf("imported compose file %s defines conflicting volume %s", path, n)
}
model.Volumes[n] = volume
}
for n, secret := range imported.Secrets {
if _, ok := model.Secrets[n]; ok {
return fmt.Errorf("imported compose file %s defines conflicting secret %s", path, n)
}
model.Secrets[n] = secret
}
for n, config := range imported.Configs {
if _, ok := model.Configs[n]; ok {
return fmt.Errorf("imported compose file %s defines conflicting config %s", path, n)
}
model.Configs[n] = config
}
return nil
}

View File

@@ -56,6 +56,8 @@ type Options struct {
SkipConsistencyCheck bool
// Skip extends
SkipExtends bool
// SkipInclude will ignore `include` and only load model from file(s) set by ConfigDetails
SkipInclude bool
// Interpolation options
Interpolate *interp.Options
// Discard 'env_file' entries after resolving to 'environment' section
@@ -68,6 +70,24 @@ type Options struct {
Profiles []string
}
func (o *Options) clone() *Options {
return &Options{
SkipValidation: o.SkipValidation,
SkipInterpolation: o.SkipInterpolation,
SkipNormalization: o.SkipNormalization,
ResolvePaths: o.ResolvePaths,
ConvertWindowsPaths: o.ConvertWindowsPaths,
SkipConsistencyCheck: o.SkipConsistencyCheck,
SkipExtends: o.SkipExtends,
SkipInclude: o.SkipInclude,
Interpolate: o.Interpolate,
discardEnvFiles: o.discardEnvFiles,
projectName: o.projectName,
projectNameImperativelySet: o.projectNameImperativelySet,
Profiles: o.Profiles,
}
}
func (o *Options) SetProjectName(name string, imperativelySet bool) {
o.projectName = name
o.projectNameImperativelySet = imperativelySet
@@ -185,6 +205,7 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
LookupValue: configDetails.LookupEnv,
TypeCastMapping: interpolateTypeCastMapping,
},
ResolvePaths: true,
}
for _, op := range options {
@@ -195,8 +216,22 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
if err != nil {
return nil, err
}
opts.projectName = projectName
return load(configDetails, opts, nil)
}
func load(configDetails types.ConfigDetails, opts *Options, loaded []string) (*types.Project, error) {
var model *types.Config
mainFile := configDetails.ConfigFiles[0].Filename
for _, f := range loaded {
if f == mainFile {
loaded = append(loaded, mainFile)
return nil, errors.Errorf("include cycle detected:\n%s\n include %s", loaded[0], strings.Join(loaded[1:], "\n include "))
}
}
loaded = append(loaded, mainFile)
for i, file := range configDetails.ConfigFiles {
var postProcessor PostProcessor
configDict := file.Config
@@ -231,10 +266,18 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
return nil, err
}
if !opts.SkipInclude {
cfg, err = loadInclude(configDetails, cfg, opts, loaded)
if err != nil {
return nil, err
}
}
if i == 0 {
model = cfg
continue
}
merged, err := merge([]*types.Config{model, cfg})
if err != nil {
return nil, err
@@ -248,16 +291,8 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
model = merged
}
for _, s := range model.Services {
var newEnvFiles types.StringList
for _, ef := range s.EnvFile {
newEnvFiles = append(newEnvFiles, absPath(configDetails.WorkingDir, ef))
}
s.EnvFile = newEnvFiles
}
project := &types.Project{
Name: projectName,
Name: opts.projectName,
WorkingDir: configDetails.WorkingDir,
Services: model.Services,
Networks: model.Networks,
@@ -269,14 +304,30 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
}
if !opts.SkipNormalization {
err = Normalize(project, opts.ResolvePaths)
err := Normalize(project)
if err != nil {
return nil, err
}
}
if opts.ResolvePaths {
err := ResolveRelativePaths(project)
if err != nil {
return nil, err
}
}
if opts.ConvertWindowsPaths {
for i, service := range project.Services {
for j, volume := range service.Volumes {
service.Volumes[j] = convertVolumePath(volume)
}
project.Services[i] = service
}
}
if !opts.SkipConsistencyCheck {
err = checkConsistency(project)
err := checkConsistency(project)
if err != nil {
return nil, err
}
@@ -287,7 +338,7 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
}
project.ApplyProfiles(opts.Profiles)
err = project.ResolveServicesEnvironment(opts.discardEnvFiles)
err := project.ResolveServicesEnvironment(opts.discardEnvFiles)
return project, err
}
@@ -419,7 +470,6 @@ func loadSections(filename string, config map[string]interface{}, configDetails
if err != nil {
return nil, err
}
cfg.Networks, err = LoadNetworks(getSection(config, "networks"))
if err != nil {
return nil, err
@@ -428,11 +478,15 @@ func loadSections(filename string, config map[string]interface{}, configDetails
if err != nil {
return nil, err
}
cfg.Secrets, err = LoadSecrets(getSection(config, "secrets"), configDetails, opts.ResolvePaths)
cfg.Secrets, err = LoadSecrets(getSection(config, "secrets"))
if err != nil {
return nil, err
}
cfg.Configs, err = LoadConfigObjs(getSection(config, "configs"), configDetails, opts.ResolvePaths)
cfg.Configs, err = LoadConfigObjs(getSection(config, "configs"))
if err != nil {
return nil, err
}
cfg.Include, err = LoadIncludeConfig(getSequence(config, "include"))
if err != nil {
return nil, err
}
@@ -451,6 +505,14 @@ func getSection(config map[string]interface{}, key string) map[string]interface{
return section.(map[string]interface{})
}
func getSequence(config map[string]interface{}, key string) []interface{} {
section, ok := config[key]
if !ok {
return make([]interface{}, 0)
}
return section.([]interface{})
}
// ForbiddenPropertiesError is returned when there are properties in the Compose
// file that are forbidden.
type ForbiddenPropertiesError struct {
@@ -515,6 +577,7 @@ func createTransformHook(additionalTransformers ...Transformer) mapstructure.Dec
reflect.TypeOf(types.ExtendsConfig{}): transformExtendsConfig,
reflect.TypeOf(types.DeviceRequest{}): transformServiceDeviceRequest,
reflect.TypeOf(types.SSHConfig{}): transformSSHConfig,
reflect.TypeOf(types.IncludeConfig{}): transformIncludeConfig,
}
for _, transformer := range additionalTransformers {
@@ -605,6 +668,7 @@ func LoadServices(filename string, servicesDict map[string]interface{}, workingD
for k, v := range x.(map[string]interface{}) {
servicesDict[k] = v
}
delete(servicesDict, extensions)
}
for name := range servicesDict {
@@ -633,7 +697,7 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter
target = map[string]interface{}{}
}
serviceConfig, err := LoadService(name, target.(map[string]interface{}), workingDir, lookupEnv, opts.ResolvePaths, opts.ConvertWindowsPaths)
serviceConfig, err := LoadService(name, target.(map[string]interface{}))
if err != nil {
return nil, err
}
@@ -671,21 +735,9 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter
// make the paths relative to `file` rather than `baseFilePath` so
// that the resulting paths won't be absolute if `file` isn't an
// absolute path.
baseFileParent := filepath.Dir(file)
if baseService.Build != nil {
baseService.Build.Context = resolveBuildContextPath(baseFileParent, baseService.Build.Context)
}
for i, vol := range baseService.Volumes {
if vol.Type != types.VolumeTypeBind {
continue
}
baseService.Volumes[i].Source = resolveMaybeUnixPath(vol.Source, baseFileParent, lookupEnv)
}
for i, envFile := range baseService.EnvFile {
baseService.EnvFile[i] = resolveMaybeUnixPath(envFile, baseFileParent, lookupEnv)
}
ResolveServiceRelativePaths(baseFileParent, baseService)
}
serviceConfig, err = _merge(baseService, serviceConfig)
@@ -698,22 +750,9 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter
return serviceConfig, nil
}
func resolveBuildContextPath(baseFileParent string, context string) string {
// Checks if the context is an HTTP(S) URL or a remote git repository URL
for _, prefix := range []string{"https://", "http://", "git://", "github.com/", "git@"} {
if strings.HasPrefix(context, prefix) {
return context
}
}
// Note that the Dockerfile is always defined relative to the
// build context, so there's no need to update the Dockerfile field.
return absPath(baseFileParent, context)
}
// LoadService produces a single ServiceConfig from a compose file Dict
// the serviceDict is not validated if directly used. Use Load() to enable validation
func LoadService(name string, serviceDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, resolvePaths bool, convertPaths bool) (*types.ServiceConfig, error) {
func LoadService(name string, serviceDict map[string]interface{}) (*types.ServiceConfig, error) {
serviceConfig := &types.ServiceConfig{
Scale: 1,
}
@@ -730,13 +769,6 @@ func LoadService(name string, serviceDict map[string]interface{}, workingDir str
return nil, errors.New(`invalid mount config for type "bind": field Source must not be empty`)
}
if resolvePaths || convertPaths {
volume = resolveVolumePath(volume, workingDir, lookupEnv)
}
if convertPaths {
volume = convertVolumePath(volume)
}
serviceConfig.Volumes[i] = volume
}
@@ -758,8 +790,8 @@ func convertVolumePath(volume types.ServiceVolumeConfig) types.ServiceVolumeConf
return volume
}
func resolveMaybeUnixPath(path string, workingDir string, lookupEnv template.Mapping) string {
filePath := expandUser(path, lookupEnv)
func resolveMaybeUnixPath(workingDir string, path string) string {
filePath := expandUser(path)
// Check if source is an absolute path (either Unix or Windows), to
// handle a Windows client with a Unix daemon or vice-versa.
//
@@ -772,20 +804,8 @@ func resolveMaybeUnixPath(path string, workingDir string, lookupEnv template.Map
return filePath
}
func resolveVolumePath(volume types.ServiceVolumeConfig, workingDir string, lookupEnv template.Mapping) types.ServiceVolumeConfig {
volume.Source = resolveMaybeUnixPath(volume.Source, workingDir, lookupEnv)
return volume
}
func resolveSecretsPath(secret types.SecretConfig, workingDir string, lookupEnv template.Mapping) types.SecretConfig {
if !secret.External.External && secret.File != "" {
secret.File = resolveMaybeUnixPath(secret.File, workingDir, lookupEnv)
}
return secret
}
// TODO: make this more robust
func expandUser(path string, lookupEnv template.Mapping) string {
func expandUser(path string) string {
if strings.HasPrefix(path, "~") {
home, err := os.UserHomeDir()
if err != nil {
@@ -885,44 +905,39 @@ func LoadVolumes(source map[string]interface{}) (map[string]types.VolumeConfig,
// LoadSecrets produces a SecretConfig map from a compose file Dict
// the source Dict is not validated if directly used. Use Load() to enable validation
func LoadSecrets(source map[string]interface{}, details types.ConfigDetails, resolvePaths bool) (map[string]types.SecretConfig, error) {
func LoadSecrets(source map[string]interface{}) (map[string]types.SecretConfig, error) {
secrets := make(map[string]types.SecretConfig)
if err := Transform(source, &secrets); err != nil {
return secrets, err
}
for name, secret := range secrets {
obj, err := loadFileObjectConfig(name, "secret", types.FileObjectConfig(secret), details, false)
obj, err := loadFileObjectConfig(name, "secret", types.FileObjectConfig(secret))
if err != nil {
return nil, err
}
secretConfig := types.SecretConfig(obj)
if resolvePaths {
secretConfig = resolveSecretsPath(secretConfig, details.WorkingDir, details.LookupEnv)
}
secrets[name] = secretConfig
secrets[name] = types.SecretConfig(obj)
}
return secrets, nil
}
// LoadConfigObjs produces a ConfigObjConfig map from a compose file Dict
// the source Dict is not validated if directly used. Use Load() to enable validation
func LoadConfigObjs(source map[string]interface{}, details types.ConfigDetails, resolvePaths bool) (map[string]types.ConfigObjConfig, error) {
func LoadConfigObjs(source map[string]interface{}) (map[string]types.ConfigObjConfig, error) {
configs := make(map[string]types.ConfigObjConfig)
if err := Transform(source, &configs); err != nil {
return configs, err
}
for name, config := range configs {
obj, err := loadFileObjectConfig(name, "config", types.FileObjectConfig(config), details, resolvePaths)
obj, err := loadFileObjectConfig(name, "config", types.FileObjectConfig(config))
if err != nil {
return nil, err
}
configConfig := types.ConfigObjConfig(obj)
configs[name] = configConfig
configs[name] = types.ConfigObjConfig(obj)
}
return configs, nil
}
func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfig, details types.ConfigDetails, resolvePaths bool) (types.FileObjectConfig, error) {
func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfig) (types.FileObjectConfig, error) {
// if "external: true"
switch {
case obj.External.External:
@@ -942,26 +957,11 @@ func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfi
if obj.File != "" {
return obj, errors.Errorf("%[1]s %[2]s: %[1]s.driver and %[1]s.file conflict; only use %[1]s.driver", objType, name)
}
default:
if obj.File != "" && resolvePaths {
obj.File = absPath(details.WorkingDir, obj.File)
}
}
return obj, nil
}
func absPath(workingDir string, filePath string) string {
if strings.HasPrefix(filePath, "~") {
home, _ := os.UserHomeDir()
return filepath.Join(home, filePath[1:])
}
if filepath.IsAbs(filePath) {
return filePath
}
return filepath.Join(workingDir, filePath)
}
var transformMapStringString TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case map[string]interface{}:
@@ -1088,13 +1088,24 @@ var transformDependsOnConfig TransformerFunc = func(data interface{}) (interface
for _, serviceIntf := range value {
service, ok := serviceIntf.(string)
if !ok {
return data, errors.Errorf("invalid type %T for service depends_on elementn, expected string", value)
return data, errors.Errorf("invalid type %T for service depends_on element, expected string", value)
}
transformed[service] = map[string]interface{}{"condition": types.ServiceConditionStarted}
transformed[service] = map[string]interface{}{"condition": types.ServiceConditionStarted, "required": true}
}
return transformed, nil
case map[string]interface{}:
return groupXFieldsIntoExtensions(data.(map[string]interface{})), nil
transformed := map[string]interface{}{}
for service, val := range value {
dependsConfigIntf, ok := val.(map[string]interface{})
if !ok {
return data, errors.Errorf("invalid type %T for service depends_on element", value)
}
if _, ok := dependsConfigIntf["required"]; !ok {
dependsConfigIntf["required"] = true
}
transformed[service] = dependsConfigIntf
}
return groupXFieldsIntoExtensions(transformed), nil
default:
return data, errors.Errorf("invalid type %T for service depends_on", value)
}

View File

@@ -150,13 +150,12 @@ func unique(slice []string) []string {
return nil
}
uniqMap := make(map[string]struct{})
var uniqSlice []string
for _, v := range slice {
uniqMap[v] = struct{}{}
}
uniqSlice := make([]string, 0, len(uniqMap))
for v := range uniqMap {
uniqSlice = append(uniqSlice, v)
if _, ok := uniqMap[v]; !ok {
uniqSlice = append(uniqSlice, v)
uniqMap[v] = struct{}{}
}
}
return uniqSlice
}

View File

@@ -18,8 +18,6 @@ package loader
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/compose-spec/compose-go/errdefs"
@@ -29,19 +27,7 @@ import (
)
// Normalize compose project by moving deprecated attributes to their canonical position and injecting implicit defaults
func Normalize(project *types.Project, resolvePaths bool) error {
absWorkingDir, err := filepath.Abs(project.WorkingDir)
if err != nil {
return err
}
project.WorkingDir = absWorkingDir
absComposeFiles, err := absComposeFiles(project.ComposeFiles)
if err != nil {
return err
}
project.ComposeFiles = absComposeFiles
func Normalize(project *types.Project) error {
if project.Networks == nil {
project.Networks = make(map[string]types.NetworkConfig)
}
@@ -51,8 +37,7 @@ func Normalize(project *types.Project, resolvePaths bool) error {
project.Networks["default"] = types.NetworkConfig{}
}
err = relocateExternalName(project)
if err != nil {
if err := relocateExternalName(project); err != nil {
return err
}
@@ -72,38 +57,16 @@ func Normalize(project *types.Project, resolvePaths bool) error {
}
if s.Build != nil {
if s.Build.Context == "" {
s.Build.Context = "."
}
if s.Build.Dockerfile == "" && s.Build.DockerfileInline == "" {
s.Build.Dockerfile = "Dockerfile"
}
if resolvePaths {
// Build context might be a remote http/git context. Unfortunately supported "remote"
// syntax is highly ambiguous in moby/moby and not defined by compose-spec,
// so let's assume runtime will check
localContext := absPath(project.WorkingDir, s.Build.Context)
if _, err := os.Stat(localContext); err == nil {
s.Build.Context = localContext
}
for name, path := range s.Build.AdditionalContexts {
if strings.Contains(path, "://") { // `docker-image://` or any builder specific context type
continue
}
path = absPath(project.WorkingDir, path)
if _, err := os.Stat(path); err == nil {
s.Build.AdditionalContexts[name] = path
}
}
}
s.Build.Args = s.Build.Args.Resolve(fn)
}
for j, f := range s.EnvFile {
s.EnvFile[j] = absPath(project.WorkingDir, f)
}
s.Environment = s.Environment.Resolve(fn)
if s.Extends != nil && s.Extends.File != "" {
s.Extends.File = absPath(project.WorkingDir, s.Extends.File)
}
for _, link := range s.Links {
parts := strings.Split(link, ":")
if len(parts) == 2 {
@@ -112,6 +75,7 @@ func Normalize(project *types.Project, resolvePaths bool) error {
s.DependsOn = setIfMissing(s.DependsOn, link, types.ServiceDependency{
Condition: types.ServiceConditionStarted,
Restart: true,
Required: true,
})
}
@@ -121,6 +85,7 @@ func Normalize(project *types.Project, resolvePaths bool) error {
s.DependsOn = setIfMissing(s.DependsOn, name, types.ServiceDependency{
Condition: types.ServiceConditionStarted,
Restart: true,
Required: true,
})
}
}
@@ -131,6 +96,7 @@ func Normalize(project *types.Project, resolvePaths bool) error {
s.DependsOn = setIfMissing(s.DependsOn, spec[0], types.ServiceDependency{
Condition: types.ServiceConditionStarted,
Restart: false,
Required: true,
})
}
}
@@ -160,14 +126,6 @@ func Normalize(project *types.Project, resolvePaths bool) error {
project.Services[i] = s
}
for name, config := range project.Volumes {
if config.Driver == "local" && config.DriverOpts["o"] == "bind" {
// This is actually a bind mount
config.DriverOpts["device"] = absPath(project.WorkingDir, config.DriverOpts["device"])
project.Volumes[name] = config
}
}
setNameFromKey(project)
return nil
@@ -223,6 +181,7 @@ func inferImplicitDependencies(service *types.ServiceConfig) {
if _, ok := service.DependsOn[d]; !ok {
service.DependsOn[d] = types.ServiceDependency{
Condition: types.ServiceConditionStarted,
Required: true,
}
}
}
@@ -254,18 +213,6 @@ func relocateScale(s *types.ServiceConfig) error {
return nil
}
func absComposeFiles(composeFiles []string) ([]string, error) {
absComposeFiles := make([]string, len(composeFiles))
for i, composeFile := range composeFiles {
absComposefile, err := filepath.Abs(composeFile)
if err != nil {
return nil, err
}
absComposeFiles[i] = absComposefile
}
return absComposeFiles, nil
}
// Resources with no explicit name are actually named by their key in map
func setNameFromKey(project *types.Project) {
for i, n := range project.Networks {

View File

@@ -0,0 +1,135 @@
/*
Copyright 2020 The Compose Specification Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package loader
import (
"os"
"path/filepath"
"strings"
"github.com/compose-spec/compose-go/types"
)
// ResolveRelativePaths resolves relative paths based on project WorkingDirectory
func ResolveRelativePaths(project *types.Project) error {
absWorkingDir, err := filepath.Abs(project.WorkingDir)
if err != nil {
return err
}
project.WorkingDir = absWorkingDir
absComposeFiles, err := absComposeFiles(project.ComposeFiles)
if err != nil {
return err
}
project.ComposeFiles = absComposeFiles
for i, s := range project.Services {
ResolveServiceRelativePaths(project.WorkingDir, &s)
project.Services[i] = s
}
for i, obj := range project.Configs {
if obj.File != "" {
obj.File = absPath(project.WorkingDir, obj.File)
project.Configs[i] = obj
}
}
for i, obj := range project.Secrets {
if obj.File != "" {
obj.File = resolveMaybeUnixPath(project.WorkingDir, obj.File)
project.Secrets[i] = obj
}
}
for name, config := range project.Volumes {
if config.Driver == "local" && config.DriverOpts["o"] == "bind" {
// This is actually a bind mount
config.DriverOpts["device"] = resolveMaybeUnixPath(project.WorkingDir, config.DriverOpts["device"])
project.Volumes[name] = config
}
}
return nil
}
func ResolveServiceRelativePaths(workingDir string, s *types.ServiceConfig) {
if s.Build != nil {
if !isRemoteContext(s.Build.Context) {
s.Build.Context = absPath(workingDir, s.Build.Context)
}
for name, path := range s.Build.AdditionalContexts {
if strings.Contains(path, "://") { // `docker-image://` or any builder specific context type
continue
}
if isRemoteContext(path) {
continue
}
s.Build.AdditionalContexts[name] = absPath(workingDir, path)
}
}
for j, f := range s.EnvFile {
s.EnvFile[j] = absPath(workingDir, f)
}
if s.Extends != nil && s.Extends.File != "" {
s.Extends.File = absPath(workingDir, s.Extends.File)
}
for i, vol := range s.Volumes {
if vol.Type != types.VolumeTypeBind {
continue
}
s.Volumes[i].Source = resolveMaybeUnixPath(workingDir, vol.Source)
}
}
func absPath(workingDir string, filePath string) string {
if strings.HasPrefix(filePath, "~") {
home, _ := os.UserHomeDir()
return filepath.Join(home, filePath[1:])
}
if filepath.IsAbs(filePath) {
return filePath
}
return filepath.Join(workingDir, filePath)
}
func absComposeFiles(composeFiles []string) ([]string, error) {
for i, composeFile := range composeFiles {
absComposefile, err := filepath.Abs(composeFile)
if err != nil {
return nil, err
}
composeFiles[i] = absComposefile
}
return composeFiles, nil
}
// isRemoteContext returns true if the value is a Git reference or HTTP(S) URL.
//
// Any other value is assumed to be a local filesystem path and returns false.
//
// See: https://github.com/moby/buildkit/blob/18fc875d9bfd6e065cd8211abc639434ba65aa56/frontend/dockerui/context.go#L76-L79
func isRemoteContext(maybeURL string) bool {
for _, prefix := range []string{"https://", "http://", "git://", "ssh://", "github.com/", "git@"} {
if strings.HasPrefix(maybeURL, prefix) {
return true
}
}
return false
}

View File

@@ -1,5 +1,5 @@
{
"$schema": "http://json-schema.org/draft/2019-09/schema#",
"$schema": "https://json-schema.org/draft/2019-09/schema#",
"id": "compose_spec.json",
"type": "object",
"title": "Compose Specification",
@@ -17,6 +17,15 @@
"description": "define the Compose project name, until user defines one explicitly."
},
"include": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/include"
},
"description": "compose sub-projects to be included."
},
"services": {
"id": "#/properties/services",
"type": "object",
@@ -84,6 +93,7 @@
"properties": {
"deploy": {"$ref": "#/definitions/deployment"},
"annotations": {"$ref": "#/definitions/list_or_dict"},
"attach": {"type": "boolean"},
"build": {
"oneOf": [
{"type": "string"},
@@ -181,6 +191,10 @@
"additionalProperties": false,
"properties": {
"restart": {"type": "boolean"},
"required": {
"type": "boolean",
"default": true
},
"condition": {
"type": "string",
"enum": ["service_started", "service_healthy", "service_completed_successfully"]
@@ -443,7 +457,8 @@
]
},
"timeout": {"type": "string", "format": "duration"},
"start_period": {"type": "string", "format": "duration"}
"start_period": {"type": "string", "format": "duration"},
"start_interval": {"type": "string", "format": "duration"}
},
"additionalProperties": false,
"patternProperties": {"^x-": {}}
@@ -588,6 +603,22 @@
}
},
"include": {
"id": "#/definitions/include",
"oneOf": [
{"type": "string"},
{
"type": "object",
"properties": {
"path": {"$ref": "#/definitions/string_or_list"},
"env_file": {"$ref": "#/definitions/string_or_list"},
"project_directory": {"type": "string"}
},
"additionalProperties": false
}
]
},
"network": {
"id": "#/definitions/network",
"type": ["object", "null"],

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