Compare commits

...

85 Commits

Author SHA1 Message Date
Tõnis Tiigi
181348397c Merge pull request #2742 from tonistiigi/otel-build
build: add OTEL span around build function
2024-10-28 16:16:08 -07:00
Tõnis Tiigi
ad371e428e Merge pull request #2759 from tonistiigi/vendor-buildkit-v0.17.0-rc2
vendor: update buildkit to v0.17.0-rc2
2024-10-28 16:15:19 -07:00
Tonis Tiigi
f35dae3726 build: add OTEL span around build function
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2024-10-28 15:53:22 -07:00
Tonis Tiigi
6fcc6853d9 vendor: update buildkit to v0.17.0-rc2
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2024-10-28 15:39:50 -07:00
Tõnis Tiigi
202c390fca Merge pull request #2722 from crazy-max/test-details-link-exp
build: fix build details link in experimental mode
2024-10-28 10:03:10 -07:00
Tõnis Tiigi
2bdf451b68 Merge pull request #2754 from crazy-max/call-localstate
build: don't generate local state for subrequests
2024-10-25 11:06:22 -07:00
CrazyMax
658ed584c7 Merge pull request #2746 from jsternberg/buildx-profiles
pprof: take cpu and memory profiles by setting environment variables
2024-10-25 15:52:35 +02:00
CrazyMax
886ae21e93 build: don't generate local state for subrequests
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-10-25 11:06:25 +02:00
Jonathan A. Sternberg
cf7a9aa084 pprof: take cpu and memory profiles by setting environment variables
When run in standalone mode, the environment variables
`DOCKER_BUILDX_CPU_PROFILE` and `DOCKER_BUILDX_MEM_PROFILE` will cause
profiles to be written by the CLI.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-10-24 09:56:27 -05:00
CrazyMax
eb15c667b9 controller: rename ref to sessionID and set buildRef back to ref
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-10-24 15:37:18 +02:00
CrazyMax
1060328a96 build: fix build details link in experimental mode
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-10-23 20:31:17 +02:00
Tõnis Tiigi
746eadd16e Merge pull request #2745 from crazy-max/detect-sudo
config: fix file/folder ownership
2024-10-23 10:04:38 -07:00
CrazyMax
f89f861999 config: fix file/folder ownership
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-10-23 18:23:14 +02:00
Tõnis Tiigi
08a973a148 Merge pull request #2741 from crazy-max/cli-fix-unknown-command
cli: error out on unknown command
2024-10-23 08:47:44 -07:00
CrazyMax
cc286e2ef5 cli: error out on unknown command
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-10-18 14:04:16 +02:00
CrazyMax
9f0ebd2643 Merge pull request #2744 from dvdksn/bake-docs-pull-bool
docs: bake pull attr is a boolean
2024-10-17 10:36:10 +02:00
David Karlsson
680cdf1179 docs: bake pull attr is a boolean
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-10-17 10:26:29 +02:00
Tõnis Tiigi
8d32cabc22 Merge pull request #2740 from dvdksn/src-attr-secret-env
docs: clarify options for secret types (file, env)
2024-10-16 12:20:58 -07:00
David Karlsson
239930c998 chore: fix FromAsCasing in Dockerfile example
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-10-16 15:58:34 +02:00
David Karlsson
8d7f69883f docs: clarify options for secret types (file, env)
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-10-16 15:57:58 +02:00
Tõnis Tiigi
1de332530f Merge pull request #2729 from thaJeztah/touchup_security
touch-up security policy
2024-10-10 09:57:55 -07:00
CrazyMax
65c4756473 Merge pull request #2728 from thaJeztah/gha_permissions
gha: set default permissions to "contents: read"
2024-10-09 09:43:33 +02:00
Tõnis Tiigi
d3ff70ace0 Merge pull request #2724 from jsternberg/vtproto
hack: generate vtproto files for buildx
2024-10-08 17:04:19 -07:00
Tonis Tiigi
14de641bec vendor: update buildkit to v0.17.0-rc1
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2024-10-08 16:54:03 -07:00
Sebastiaan van Stijn
1ce3e6a221 touch-up security policy
Touch-up the security policy to make the OpenSSF scorecard
slightly happier;
https://securityscorecards.dev/viewer/?uri=github.com/docker/buildx

    Warn: One or no descriptive hints of disclosure, vulnerability, and/or timelines in security policy

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-09 01:22:26 +02:00
Sebastiaan van Stijn
b1a13bb740 gha: set default permissions to "contents: read"
make the OpenSSF scorecard slightly happier;
https://securityscorecards.dev/viewer/?uri=github.com/docker/buildx

    Warn: no topLevel permission defined: .github/workflows/build.yml:1
    Warn: topLevel 'security-events' permission set to 'write': .github/workflows/codeql.yml:13
    Warn: no topLevel permission defined: .github/workflows/docs-release.yml:1
    Warn: no topLevel permission defined: .github/workflows/docs-upstream.yml:1
    Warn: no topLevel permission defined: .github/workflows/e2e.yml:1
    Warn: no topLevel permission defined: .github/workflows/labeler.yml:1
    Warn: no topLevel permission defined: .github/workflows/validate.yml:1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-09 01:07:18 +02:00
Jonathan A. Sternberg
64c5139ab6 hack: generate vtproto files for buildx
Integrates vtproto into buildx. The generated files dockerfile has been
modified to copy the buildkit equivalent file to ensure files are laid
out in the appropriate way for imports.

An import has also been included to change the grpc codec to the version
in buildkit that supports vtproto. This will allow buildx to utilize the
speed and memory improvements from that.

Also updates the gc control options for prune.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-10-08 13:35:06 -05:00
Tõnis Tiigi
d353f5f6ba Merge pull request #2717 from crazy-max/fix-ls-notrunc
ls: ensure deterministic output for truncated platforms
2024-10-04 12:52:45 -07:00
Tõnis Tiigi
4507a492da Merge pull request #2719 from jsternberg/bake-remote-size
bake: raise maximum size limit and fix size check
2024-10-04 12:51:28 -07:00
Jonathan A. Sternberg
9fc6f39d71 bake: raise maximum size limit and fix size check
Similar to https://github.com/docker/buildx/pull/2716.

Use the file size rather than the proto size, raise the allowed limit to
the same value for consistency, and improve the error message to include
the limit in human units.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-10-04 09:11:07 -05:00
CrazyMax
f6a27a664b ls: ensure deterministic output for truncated platforms
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-10-04 09:27:03 +02:00
Tõnis Tiigi
48153169d8 Merge pull request #2716 from jsternberg/dockerfile-size-limit
build: raise maximum size limit for dockerfile and fix size check
2024-10-03 14:25:31 -07:00
Jonathan A. Sternberg
d7de22c61f build: raise maximum size limit for dockerfile and fix size check
Raise the maximum size limit for the dockerfile and correct the size
check. The size check was intended to use the size attribute from the
file stat, but the original gogo version confused the `Size()`
method (which returned the size of the proto message) with the `Size`
attribute (which was named `Size_`).

During the conversion, we noticed the mistake but kept the incorrect
behavior for the sake of keeping the conversion simple.

This also raises the maximum limit because 512 kB is likely a bit too
conservative. The limit has been raised to 2 MB and the limit has been
included in the error message.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-10-03 12:12:40 -05:00
Tõnis Tiigi
7c91f3d0dd Merge pull request #2138 from crazy-max/ls-notrunc
ls: no-trunc opt
2024-10-03 08:21:09 -07:00
CrazyMax
820f5e77ed ls: no-trunc opt
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-10-03 11:15:46 +02:00
Tõnis Tiigi
1db8f6789f Merge pull request #2713 from jsternberg/gogoproto-remove
protobuf: remove gogoproto
2024-10-02 15:39:47 -07:00
Jonathan A. Sternberg
b35a0f4718 protobuf: remove gogoproto
Removes gogo/protobuf from buildx and updates to a version of
moby/buildkit where gogo is removed.

This also changes how the proto files are generated. This is because
newer versions of protobuf are more strict about name conflicts. If two
files have the same name (even if they are relative paths) and are used
in different protoc commands, they'll conflict in the registry.

Since protobuf file generation doesn't work very well with
`paths=source_relative`, this removes the `go:generate` expression and
just relies on the dockerfile to perform the generation.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-10-02 15:51:59 -05:00
CrazyMax
8e47387d02 Merge pull request #2701 from tonistiigi/fix-link-entitlements
bake: fix linking to targets with entitlements
2024-09-25 10:43:21 +02:00
CrazyMax
fdda92f304 Merge pull request #2703 from docker/dependabot/github_actions/peter-evans/create-pull-request-7.0.5
build(deps): bump peter-evans/create-pull-request from 7.0.3 to 7.0.5
2024-09-25 10:42:46 +02:00
CrazyMax
d078a3047d Merge pull request #2705 from tonistiigi/call-fallback
build: use better references for --call fallback images
2024-09-25 10:42:24 +02:00
Tõnis Tiigi
f102ad73a8 Merge pull request #2672 from daghack/dockerfile-path-on-warnings
build: display Dockerfile path on check warnings
2024-09-19 08:30:48 -07:00
Talon Bowler
671bd1b54d Update to pass DockerMappingSrc and Dst in with Inputs, and return Inputs through Build
Signed-off-by: Talon Bowler <talon.bowler@docker.com>
2024-09-18 20:56:31 -07:00
Tonis Tiigi
f8657e8798 build: use better references for --call fallback images
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2024-09-18 18:43:40 -07:00
dependabot[bot]
61d9f1d981 build(deps): bump peter-evans/create-pull-request from 7.0.3 to 7.0.5
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 7.0.3 to 7.0.5.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](6cd32fd936...5e914681df)

---
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>
2024-09-18 18:49:37 +00:00
Tõnis Tiigi
9eb0318ee6 Merge pull request #2696 from crazy-max/test-fix-cleanup
test: fix missing envs when cleaning up some workers
2024-09-17 20:27:29 -07:00
CrazyMax
4528269102 Merge pull request #2699 from docker/dependabot/github_actions/peter-evans/create-pull-request-7.0.3
build(deps): bump peter-evans/create-pull-request from 7.0.2 to 7.0.3
2024-09-17 09:27:20 +02:00
CrazyMax
8d3d32e376 Merge pull request #2700 from tonistiigi/fix-link-itself
bake: fix validation for linking to itself
2024-09-17 09:25:26 +02:00
Tonis Tiigi
c60afbb25b bake: fix linking to targets with entitlements
When linked target requires entitlement, same entitlement
is also needed by the caller. Otherwise, the request will
fail when the build is processed.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2024-09-16 16:31:22 -07:00
Tonis Tiigi
9bfa8603f6 bake: fix validation for linking to itself
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2024-09-16 16:29:32 -07:00
dependabot[bot]
30e60628bf build(deps): bump peter-evans/create-pull-request from 7.0.2 to 7.0.3
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 7.0.2 to 7.0.3.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](d121e62763...6cd32fd936)

---
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>
2024-09-16 18:36:21 +00:00
CrazyMax
df0270d0cc test: fix missing envs when cleaning up some workers
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-13 14:19:46 +02:00
CrazyMax
056cf8a7ca Merge pull request #2693 from docker/dependabot/github_actions/peter-evans/create-pull-request-7.0.2
build(deps): bump peter-evans/create-pull-request from 7.0.1 to 7.0.2
2024-09-12 22:48:06 +02:00
dependabot[bot]
15c596a091 build(deps): bump peter-evans/create-pull-request from 7.0.1 to 7.0.2
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 7.0.1 to 7.0.2.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](8867c4aba1...d121e62763)

---
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>
2024-09-12 18:30:42 +00:00
CrazyMax
e950b2e478 Merge pull request #2692 from glours/bump-compose-go-v2.2.0
bump compose-go to v2.2.0
2024-09-12 19:04:35 +02:00
Guillaume Lours
4da753da79 bump compose-go to v2.2.0
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2024-09-12 18:14:18 +02:00
CrazyMax
3f81293fd4 Merge pull request #2691 from crazy-max/ci-fix-perms
ci: fix golvulncheck job permissions
2024-09-12 16:36:29 +02:00
CrazyMax
120578091f ci: fix golvulncheck job permissions
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-12 15:23:33 +02:00
Tõnis Tiigi
604b723007 Merge pull request #2684 from crazy-max/inspect-buildkitd-conf
inspect: display buildkit daemon configuration file
2024-09-11 17:32:25 -07:00
CrazyMax
528181c759 inspect: display buildkit daemon configuration file
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-12 00:16:24 +02:00
Tõnis Tiigi
cd5381900c Merge pull request #2688 from crazy-max/bump-xx
dockerfile: update xx to 1.5.0
2024-09-11 10:50:58 -07:00
Tõnis Tiigi
bba2bb4b89 Merge pull request #2686 from crazy-max/bump-buildkit
dockerfile, ci: update buildkit to latest stable
2024-09-11 10:50:40 -07:00
Tõnis Tiigi
8fd27b8c23 Merge pull request #2685 from crazy-max/skip-networkhost-conf
builder: do not set network.host entitlement flag if already set in buildkitd conf
2024-09-11 10:39:29 -07:00
Tõnis Tiigi
6dcc8d8b84 Merge pull request #2689 from crazy-max/bake-fix-network-field
bake: fix missing omitempty and optional tags for network field
2024-09-11 10:35:33 -07:00
CrazyMax
9fb8b04b64 bake: fix missing omitempty and optional tags for network field
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-11 14:47:01 +02:00
CrazyMax
6ba5802958 Merge pull request #2687 from crazy-max/bump-docker
dockerfile: update docker to 27.2.1
2024-09-11 13:57:09 +02:00
CrazyMax
f039670961 dockerfile: update xx to 1.5.0
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-11 12:59:36 +02:00
CrazyMax
4ec12e7e68 dockerfile: update docker to 27.2.1
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-11 12:58:33 +02:00
CrazyMax
66ed7d6162 dockerfile, ci: update buildkit to latest stable
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-11 12:51:20 +02:00
CrazyMax
617d59d70b builder: do not set network.host entitlement flag if already set in buildkitd conf
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-11 12:27:29 +02:00
CrazyMax
40f444f4b8 Merge pull request #2680 from crazy-max/update-buildkit
vendor: update buildkit to v0.16.0
2024-09-10 18:35:06 +02:00
CrazyMax
8201d301d5 vendor: update buildkit to v0.16.0
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-10 18:18:16 +02:00
Akihiro Suda
40ef3446f5 Merge pull request #2679 from tonistiigi/buildkit-v0.16.0-rc2
vendor: update buildkit to v0.16.0-rc2
2024-09-10 08:51:08 +09:00
Tonis Tiigi
7213b2a814 vendor: update buildkit to v0.16.0-rc2
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2024-09-09 16:29:01 -07:00
CrazyMax
9cfa25ab40 Merge pull request #2678 from thompson-shaun/mermaid-fix
Update PROJECT mermaid daigrams
2024-09-09 18:06:50 +02:00
Shaun Thompson
6db3444a25 update mermaid diagram to avoid GH mermaid issues
Signed-off-by: Shaun Thompson <shaun.thompson@docker.com>
2024-09-06 11:45:53 -04:00
CrazyMax
15e930b691 Merge pull request #2619 from thompson-shaun/project-guide
docs: add project processing guide
2024-09-06 16:37:21 +02:00
CrazyMax
abc5eaed88 Merge pull request #2676 from docker/dependabot/github_actions/peter-evans/create-pull-request-7.0.1
build(deps): bump peter-evans/create-pull-request from 7.0.0 to 7.0.1
2024-09-06 16:37:07 +02:00
Talon Bowler
f1b92e9e6c update Build commands to return dockerfile mapping for use in printing rule check warnings
Signed-off-by: Talon Bowler <talon.bowler@docker.com>
2024-09-06 07:34:13 -07:00
dependabot[bot]
ad9a5196b3 build(deps): bump peter-evans/create-pull-request from 7.0.0 to 7.0.1
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](4320041ed3...8867c4aba1)

---
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>
2024-09-05 18:55:59 +00:00
CrazyMax
db117855da Merge pull request #2675 from dvdksn/run-mount-secret-env
docs: update run mount secrets examples using env
2024-09-05 16:51:51 +02:00
CrazyMax
ecfe98df6f Merge pull request #2674 from crazy-max/update-authors
chore: update AUTHORS and mailmap
2024-09-05 15:17:12 +02:00
David Karlsson
479177eaf9 docs: update run mount secrets examples using env
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-09-05 11:51:00 +02:00
CrazyMax
194f523fe1 chore: update AUTHORS and mailmap
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-05 11:23:09 +02:00
CrazyMax
29d367bdd4 hack(authors): bump to alpine 3.20
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
2024-09-05 11:18:08 +02:00
Shaun Thompson
d6e030eda7 docs: add project processing guide
Signed-off-by: Shaun Thompson <shaun.thompson@docker.com>
2024-08-27 11:59:01 -04:00
850 changed files with 116475 additions and 112778 deletions

50
.github/SECURITY.md vendored
View File

@@ -1,12 +1,44 @@
# Reporting security issues # Security Policy
The project maintainers take security seriously. If you discover a security The maintainers of Docker Buildx take security seriously. If you discover
issue, please bring it to their attention right away! a security issue, please bring it to their attention right away!
**Please _DO NOT_ file a public issue**, instead send your report privately to ## Reporting a Vulnerability
[security@docker.com](mailto:security@docker.com).
Security reports are greatly appreciated, and we will publicly thank you for it. Please **DO NOT** file a public issue, instead send your report privately
We also like to send gifts&mdash;if you're into schwag, make sure to let to [security@docker.com](mailto:security@docker.com).
us know. We currently do not offer a paid security bounty program, but are not
ruling it out in the future. Reporter(s) can expect a response within 72 hours, acknowledging the issue was
received.
## Review Process
After receiving the report, an initial triage and technical analysis is
performed to confirm the report and determine its scope. We may request
additional information in this stage of the process.
Once a reviewer has confirmed the relevance of the report, a draft security
advisory will be created on GitHub. The draft advisory will be used to discuss
the issue with maintainers, the reporter(s), and where applicable, other
affected parties under embargo.
If the vulnerability is accepted, a timeline for developing a patch, public
disclosure, and patch release will be determined. If there is an embargo period
on public disclosure before the patch release, the reporter(s) are expected to
participate in the discussion of the timeline and abide by agreed upon dates
for public disclosure.
## Accreditation
Security reports are greatly appreciated and we will publicly thank you,
although we will keep your name confidential if you request it. We also like to
send gifts - if you're into swag, make sure to let us know. We do not currently
offer a paid security bounty program at this time.
## Supported Versions
Once a new feature release is cut, support for the previous feature release is
discontinued. An exception may be made for urgent security releases that occur
shortly after a new feature release. Buildx does not offer LTS (Long-Term Support)
releases. Refer to the [Support Policy](https://github.com/docker/buildx/blob/master/PROJECT.md#support-policy)
for further details.

View File

@@ -1,5 +1,14 @@
name: build name: build
# Default to 'contents: read', which grants actions to read commits.
#
# If any permission is set, any permission not included in the list is
# implicitly set to "none".
#
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@@ -45,9 +54,9 @@ jobs:
- master - master
- latest - latest
- buildx-stable-1 - buildx-stable-1
- v0.15.2
- v0.14.1 - v0.14.1
- v0.13.2 - v0.13.2
- v0.12.5
worker: worker:
- docker-container - docker-container
- remote - remote
@@ -220,6 +229,8 @@ jobs:
permissions: permissions:
# required to write sarif report # required to write sarif report
security-events: write security-events: write
# required to check out the repository
contents: read
steps: steps:
- -
name: Checkout name: Checkout

View File

@@ -1,5 +1,14 @@
name: codeql name: codeql
# Default to 'contents: read', which grants actions to read commits.
#
# If any permission is set, any permission not included in the list is
# implicitly set to "none".
#
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
contents: read
on: on:
push: push:
branches: branches:
@@ -7,16 +16,16 @@ on:
- 'v[0-9]*' - 'v[0-9]*'
pull_request: pull_request:
permissions:
actions: read
contents: read
security-events: write
env: env:
GO_VERSION: "1.22" GO_VERSION: "1.22"
jobs: jobs:
codeql: codeql:
permissions:
actions: read
contents: read
security-events: write
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- -

View File

@@ -1,5 +1,14 @@
name: docs-release name: docs-release
# Default to 'contents: read', which grants actions to read commits.
#
# If any permission is set, any permission not included in the list is
# implicitly set to "none".
#
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
contents: read
on: on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
@@ -57,7 +66,7 @@ jobs:
VENDOR_MODULE: github.com/docker/buildx@${{ env.RELEASE_NAME }} VENDOR_MODULE: github.com/docker/buildx@${{ env.RELEASE_NAME }}
- -
name: Create PR on docs repo name: Create PR on docs repo
uses: peter-evans/create-pull-request@4320041ed380b20e97d388d56a7fb4f9b8c20e79 # v7.0.0 uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
with: with:
token: ${{ secrets.GHPAT_DOCS_DISPATCH }} token: ${{ secrets.GHPAT_DOCS_DISPATCH }}
push-to-fork: docker-tools-robot/docker.github.io push-to-fork: docker-tools-robot/docker.github.io

View File

@@ -3,6 +3,15 @@
# https://github.com/docker/docker.github.io/blob/98c7c9535063ae4cd2cd0a31478a21d16d2f07a3/docker-bake.hcl#L34-L36 # https://github.com/docker/docker.github.io/blob/98c7c9535063ae4cd2cd0a31478a21d16d2f07a3/docker-bake.hcl#L34-L36
name: docs-upstream name: docs-upstream
# Default to 'contents: read', which grants actions to read commits.
#
# If any permission is set, any permission not included in the list is
# implicitly set to "none".
#
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true

View File

@@ -1,5 +1,14 @@
name: e2e name: e2e
# Default to 'contents: read', which grants actions to read commits.
#
# If any permission is set, any permission not included in the list is
# implicitly set to "none".
#
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true

View File

@@ -1,5 +1,14 @@
name: labeler name: labeler
# Default to 'contents: read', which grants actions to read commits.
#
# If any permission is set, any permission not included in the list is
# implicitly set to "none".
#
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true

View File

@@ -1,5 +1,14 @@
name: validate name: validate
# Default to 'contents: read', which grants actions to read commits.
#
# If any permission is set, any permission not included in the list is
# implicitly set to "none".
#
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true

View File

@@ -1,11 +1,25 @@
# This file lists all individuals having contributed content to the repository. # This file lists all individuals having contributed content to the repository.
# For how it is generated, see hack/dockerfiles/authors.Dockerfile. # For how it is generated, see hack/dockerfiles/authors.Dockerfile.
Batuhan Apaydın <batuhan.apaydin@trendyol.com>
Batuhan Apaydın <batuhan.apaydin@trendyol.com> <developerguy2@gmail.com>
CrazyMax <github@crazymax.dev> CrazyMax <github@crazymax.dev>
CrazyMax <github@crazymax.dev> <1951866+crazy-max@users.noreply.github.com> CrazyMax <github@crazymax.dev> <1951866+crazy-max@users.noreply.github.com>
CrazyMax <github@crazymax.dev> <crazy-max@users.noreply.github.com> CrazyMax <github@crazymax.dev> <crazy-max@users.noreply.github.com>
David Karlsson <david.karlsson@docker.com>
David Karlsson <david.karlsson@docker.com> <35727626+dvdksn@users.noreply.github.com>
jaihwan104 <jaihwan104@woowahan.com>
jaihwan104 <jaihwan104@woowahan.com> <42341126+jaihwan104@users.noreply.github.com>
Kenyon Ralph <kenyon@kenyonralph.com>
Kenyon Ralph <kenyon@kenyonralph.com> <quic_kralph@quicinc.com>
Sebastiaan van Stijn <github@gone.nl> Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn <github@gone.nl> <thaJeztah@users.noreply.github.com> Sebastiaan van Stijn <github@gone.nl> <thaJeztah@users.noreply.github.com>
Shaun Thompson <shaun.thompson@docker.com>
Shaun Thompson <shaun.thompson@docker.com> <shaun.b.thompson@gmail.com>
Silvin Lubecki <silvin.lubecki@docker.com>
Silvin Lubecki <silvin.lubecki@docker.com> <31478878+silvin-lubecki@users.noreply.github.com>
Talon Bowler <talon.bowler@docker.com>
Talon Bowler <talon.bowler@docker.com> <nolat301@gmail.com>
Tibor Vass <tibor@docker.com> Tibor Vass <tibor@docker.com>
Tibor Vass <tibor@docker.com> <tiborvass@users.noreply.github.com> Tibor Vass <tibor@docker.com> <tiborvass@users.noreply.github.com>
Tõnis Tiigi <tonistiigi@gmail.com> Tõnis Tiigi <tonistiigi@gmail.com>

69
AUTHORS
View File

@@ -1,45 +1,112 @@
# This file lists all individuals having contributed content to the repository. # This file lists all individuals having contributed content to the repository.
# For how it is generated, see hack/dockerfiles/authors.Dockerfile. # For how it is generated, see hack/dockerfiles/authors.Dockerfile.
accetto <34798830+accetto@users.noreply.github.com>
Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
Aleksa Sarai <cyphar@cyphar.com>
Alex Couture-Beil <alex@earthly.dev> Alex Couture-Beil <alex@earthly.dev>
Andrew Haines <andrew.haines@zencargo.com> Andrew Haines <andrew.haines@zencargo.com>
Andy Caldwell <andrew.caldwell@metaswitch.com>
Andy MacKinlay <admackin@users.noreply.github.com> Andy MacKinlay <admackin@users.noreply.github.com>
Anthony Poschen <zanven42@gmail.com> Anthony Poschen <zanven42@gmail.com>
Arnold Sobanski <arnold@l4g.dev>
Artur Klauser <Artur.Klauser@computer.org> Artur Klauser <Artur.Klauser@computer.org>
Batuhan Apaydın <developerguy2@gmail.com> Avi Deitcher <avi@deitcher.net>
Batuhan Apaydın <batuhan.apaydin@trendyol.com>
Ben Peachey <potherca@gmail.com>
Bertrand Paquet <bertrand.paquet@gmail.com>
Bin Du <bindu@microsoft.com> Bin Du <bindu@microsoft.com>
Brandon Philips <brandon@ifup.org> Brandon Philips <brandon@ifup.org>
Brian Goff <cpuguy83@gmail.com> Brian Goff <cpuguy83@gmail.com>
Bryce Lampe <bryce@pulumi.com>
Cameron Adams <pnzreba@gmail.com>
Christian Dupuis <cd@atomist.com>
Cory Snider <csnider@mirantis.com>
CrazyMax <github@crazymax.dev> CrazyMax <github@crazymax.dev>
David Gageot <david.gageot@docker.com>
David Karlsson <david.karlsson@docker.com>
David Scott <dave@recoil.org>
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Devin Bayer <dev@doubly.so> Devin Bayer <dev@doubly.so>
Djordje Lukic <djordje.lukic@docker.com> Djordje Lukic <djordje.lukic@docker.com>
Dmitry Makovey <dmakovey@gitlab.com>
Dmytro Makovey <dmytro.makovey@docker.com> Dmytro Makovey <dmytro.makovey@docker.com>
Donghui Wang <977675308@qq.com> Donghui Wang <977675308@qq.com>
Doug Borg <dougborg@apple.com>
Edgar Lee <edgarl@netflix.com>
Eli Treuherz <et@arenko.group>
Eliott Wiener <eliottwiener@gmail.com>
Elran Shefer <elran.shefer@velocity.tech>
faust <faustin@fala.red> faust <faustin@fala.red>
Felipe Santos <felipecassiors@gmail.com> Felipe Santos <felipecassiors@gmail.com>
Felix de Souza <fdesouza@palantir.com>
Fernando Miguel <github@FernandoMiguel.net> Fernando Miguel <github@FernandoMiguel.net>
gfrancesco <gfrancesco@users.noreply.github.com> gfrancesco <gfrancesco@users.noreply.github.com>
gracenoah <gracenoahgh@gmail.com> gracenoah <gracenoahgh@gmail.com>
Guillaume Lours <705411+glours@users.noreply.github.com>
guoguangwu <guoguangwu@magic-shield.com>
Hollow Man <hollowman@hollowman.ml> Hollow Man <hollowman@hollowman.ml>
Ian King'ori <kingorim.ian@gmail.com>
idnandre <andre@idntimes.com>
Ilya Dmitrichenko <errordeveloper@gmail.com> Ilya Dmitrichenko <errordeveloper@gmail.com>
Isaac Gaskin <isaac.gaskin@circle.com>
Jack Laxson <jackjrabbit@gmail.com> Jack Laxson <jackjrabbit@gmail.com>
jaihwan104 <jaihwan104@woowahan.com>
Jean-Yves Gastaud <jygastaud@gmail.com> Jean-Yves Gastaud <jygastaud@gmail.com>
Jhan S. Álvarez <51450231+yastanotheruser@users.noreply.github.com>
Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Jonathan Piché <jpiche@coveo.com>
Justin Chadwell <me@jedevc.com>
Kenyon Ralph <kenyon@kenyonralph.com>
khs1994 <khs1994@khs1994.com> khs1994 <khs1994@khs1994.com>
Kijima Daigo <norimaking777@gmail.com>
Kohei Tokunaga <ktokunaga.mail@gmail.com>
Kotaro Adachi <k33asby@gmail.com> Kotaro Adachi <k33asby@gmail.com>
Kushagra Mansingh <12158241+kushmansingh@users.noreply.github.com>
l00397676 <lujingxiao@huawei.com> l00397676 <lujingxiao@huawei.com>
Laura Brehm <laurabrehm@hey.com>
Laurent Goderre <laurent.goderre@docker.com>
Mark Hildreth <113933455+markhildreth-gravity@users.noreply.github.com>
Mayeul Blanzat <mayeul.blanzat@datadoghq.com>
Michal Augustyn <michal.augustyn@mail.com> Michal Augustyn <michal.augustyn@mail.com>
Milas Bowman <milas.bowman@docker.com>
Mitsuru Kariya <mitsuru.kariya@nttdata.com>
Moleus <fafufuburr@gmail.com>
Nick Santos <nick.santos@docker.com>
Nick Sieger <nick@nicksieger.com>
Nicolas De Loof <nicolas.deloof@gmail.com>
Niklas Gehlen <niklas@namespacelabs.com>
Patrick Van Stee <patrick@vanstee.me> Patrick Van Stee <patrick@vanstee.me>
Paweł Gronowski <pawel.gronowski@docker.com>
Phong Tran <tran.pho@northeastern.edu>
Qasim Sarfraz <qasimsarfraz@microsoft.com>
Rob Murray <rob.murray@docker.com>
robertlestak <robert.lestak@umusic.com>
Saul Shanabrook <s.shanabrook@gmail.com> Saul Shanabrook <s.shanabrook@gmail.com>
Sean P. Kane <spkane00@gmail.com>
Sebastiaan van Stijn <github@gone.nl> Sebastiaan van Stijn <github@gone.nl>
Shaun Thompson <shaun.thompson@docker.com>
SHIMA Tatsuya <ts1s1andn@gmail.com> SHIMA Tatsuya <ts1s1andn@gmail.com>
Silvin Lubecki <silvin.lubecki@docker.com> Silvin Lubecki <silvin.lubecki@docker.com>
Simon A. Eugster <simon.eu@gmail.com>
Solomon Hykes <sh.github.6811@hykes.org> Solomon Hykes <sh.github.6811@hykes.org>
Sumner Warren <sumner.warren@gmail.com>
Sune Keller <absukl@almbrand.dk> Sune Keller <absukl@almbrand.dk>
Talon Bowler <talon.bowler@docker.com>
Tianon Gravi <admwiggin@gmail.com>
Tibor Vass <tibor@docker.com> Tibor Vass <tibor@docker.com>
Tim Smith <tismith@rvohealth.com>
Timofey Kirillov <timofey.kirillov@flant.com>
Tyler Smith <tylerlwsmith@gmail.com>
Tõnis Tiigi <tonistiigi@gmail.com> Tõnis Tiigi <tonistiigi@gmail.com>
Ulysses Souza <ulyssessouza@gmail.com> Ulysses Souza <ulyssessouza@gmail.com>
Usual Coder <34403413+Usual-Coder@users.noreply.github.com>
Wang Jinglei <morlay.null@gmail.com> Wang Jinglei <morlay.null@gmail.com>
Wei <daviseago@gmail.com>
Wojciech M <wmiedzybrodzki@outlook.com>
Xiang Dai <764524258@qq.com> Xiang Dai <764524258@qq.com>
Zachary Povey <zachary.povey@autotrader.co.uk>
zelahi <elahi.zuhayr@gmail.com> zelahi <elahi.zuhayr@gmail.com>
Zero <tobewhatwewant@gmail.com>
zhyon404 <zhyong4@gmail.com>
Zsolt <zsolt.szeberenyi@figured.com>

View File

@@ -1,14 +1,14 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
ARG GO_VERSION=1.22 ARG GO_VERSION=1.22
ARG XX_VERSION=1.4.0 ARG XX_VERSION=1.5.0
# for testing # for testing
ARG DOCKER_VERSION=27.1.1 ARG DOCKER_VERSION=27.2.1
ARG DOCKER_CLI_VERSION=${DOCKER_VERSION} ARG DOCKER_CLI_VERSION=${DOCKER_VERSION}
ARG GOTESTSUM_VERSION=v1.9.0 ARG GOTESTSUM_VERSION=v1.9.0
ARG REGISTRY_VERSION=2.8.0 ARG REGISTRY_VERSION=2.8.0
ARG BUILDKIT_VERSION=v0.14.1 ARG BUILDKIT_VERSION=v0.16.0
ARG UNDOCK_VERSION=0.7.0 ARG UNDOCK_VERSION=0.7.0
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx

453
PROJECT.md Normal file
View File

@@ -0,0 +1,453 @@
# Project processing guide <!-- omit from toc -->
- [Project scope](#project-scope)
- [Labels](#labels)
- [Global](#global)
- [`area/`](#area)
- [`exp/`](#exp)
- [`impact/`](#impact)
- [`kind/`](#kind)
- [`needs/`](#needs)
- [`priority/`](#priority)
- [`status/`](#status)
- [Types of releases](#types-of-releases)
- [Feature releases](#feature-releases)
- [Release Candidates](#release-candidates)
- [Support Policy](#support-policy)
- [Contributing to Releases](#contributing-to-releases)
- [Patch releases](#patch-releases)
- [Milestones](#milestones)
- [Triage process](#triage-process)
- [Verify essential information](#verify-essential-information)
- [Classify the issue](#classify-the-issue)
- [Prioritization guidelines for `kind/bug`](#prioritization-guidelines-for-kindbug)
- [Issue lifecyle](#issue-lifecyle)
- [Examples](#examples)
- [Submitting a bug](#submitting-a-bug)
- [Pull request review process](#pull-request-review-process)
- [Handling stalled issues and pull requests](#handling-stalled-issues-and-pull-requests)
- [Moving to a discussion](#moving-to-a-discussion)
- [Workflow automation](#workflow-automation)
- [Exempting an issue/PR from stale bot processing](#exempting-an-issuepr-from-stale-bot-processing)
- [Updating dependencies](#updating-dependencies)
---
## Project scope
**Docker Buildx** is a Docker CLI plugin designed to extend build capabilities using BuildKit. It provides advanced features for building container images, supporting multiple builder instances, multi-node builds, and high-level build constructs. Buildx enhances the Docker build process, making it more efficient and flexible, and is compatible with both Docker and Kubernetes environments. Key features include:
- **Familiar user experience:** Buildx offers a user experience similar to legacy docker build, ensuring a smooth transition from legacy commands
- **Full BuildKit capabilities:** Leverage the full feature set of [`moby/buildkit`](https://github.com/moby/buildkit) when using the container driver
- **Multiple builder instances:** Supports the use of multiple builder instances, allowing concurrent builds and effective management and monitoring of these builders.
- **Multi-node builds:** Use multiple nodes to build cross-platform images
- **Compose integration:** Build complex, multi-services files as defined in compose
- **High-level build constructs via `bake`:** Introduces high-level build constructs for more complex build workflows
- **In-container driver support:** Support in-container drivers for both Docker and Kubernetes environments to support isolation/security.
## Labels
Below are common groups, labels, and their intended usage to support issues, pull requests, and discussion processing.
### Global
General attributes that can apply to nearly any issue or pull request.
| Label | Applies to | Description |
| ------------------- | ----------- | ------------------------------------------------------------------------- |
| `bot` | Issues, PRs | Created by a bot |
| `good first issue ` | Issues | Suitable for first-time contributors |
| `help wanted` | Issues, PRs | Assistance requested |
| `lgtm` | PRs | “Looks good to me” approval |
| `stale` | Issues, PRs | The issue/PR has not had activity for a while |
| `rotten` | Issues, PRs | The issue/PR has not had activity since being marked stale and was closed |
| `frozen` | Issues, PRs | The issue/PR should be skipped by the stale-bot |
| `dco/no` | PRs | The PR is missing a developer certificate of origin sign-off |
### `area/`
Area or component of the project affected. Please note that the table below may not be inclusive of all current options.
| Label | Applies to | Description |
| ------------------------------ | ---------- | -------------------------- |
| `area/bake` | Any | `bake` |
| `area/bake/compose` | Any | `bake/compose` |
| `area/build` | Any | `build` |
| `area/builder` | Any | `builder` |
| `area/buildkit` | Any | Relates to `moby/buildkit` |
| `area/cache` | Any | `cache` |
| `area/checks` | Any | `checks` |
| `area/ci` | Any | Project CI |
| `area/cli` | Any | `cli` |
| `area/controller` | Any | `controller` |
| `area/debug` | Any | `debug` |
| `area/dependencies` | Any | Project dependencies |
| `area/dockerfile` | Any | `dockerfile` |
| `area/docs` | Any | `docs` |
| `area/driver` | Any | `driver` |
| `area/driver/docker` | Any | `driver/docker` |
| `area/driver/docker-container` | Any | `driver/docker-container` |
| `area/driver/kubernetes` | Any | `driver/kubernetes` |
| `area/driver/remote` | Any | `driver/remote` |
| `area/feature-parity` | Any | `feature-parity` |
| `area/github-actions` | Any | `github-actions` |
| `area/hack` | Any | Project hack/support |
| `area/imagetools` | Any | `imagetools` |
| `area/metrics` | Any | `metrics` |
| `area/moby` | Any | Relates to `moby/moby` |
| `area/project` | Any | Project support |
| `area/qemu` | Any | `qemu` |
| `area/tests` | Any | Project testing |
| `area/windows` | Any | `windows` |
### `exp/`
Estimated experience level to complete the item
| Label | Applies to | Description |
| ------------------ | ---------- | ------------------------------------------------------------------------------- |
| `exp/beginner` | Issue | Suitable for contributors new to the project or technology stack |
| `exp/intermediate` | Issue | Requires some familiarity with the project and technology |
| `exp/expert` | Issue | Requires deep understanding and advanced skills with the project and technology |
### `impact/`
Potential impact areas of the issue or pull request.
| Label | Applies to | Description |
| -------------------- | ---------- | -------------------------------------------------- |
| `impact/breaking` | PR | Change is API-breaking |
| `impact/changelog` | PR | When complete, the item should be in the changelog |
| `impact/deprecation` | PR | Change is a deprecation of a feature |
### `kind/`
The type of issue, pull request or discussion
| Label | Applies to | Description |
| ------------------ | ----------------- | ------------------------------------------------------- |
| `kind/bug` | Issue, PR | Confirmed bug |
| `kind/chore` | Issue, PR | Project support tasks |
| `kind/docs` | Issue, PR | Additions or modifications to the documentation |
| `kind/duplicate` | Any | Duplicate of another item |
| `kind/enhancement` | Any | Enhancement of an existing feature |
| `kind/feature` | Any | A brand new feature |
| `kind/maybe-bug` | Issue, PR | Unconfirmed bug, turns into kind/bug when confirmed |
| `kind/proposal` | Issue, Discussion | A proposed major change |
| `kind/refactor` | Issue, PR | Refactor of existing code |
| `kind/support` | Any | A question, discussion, or other user support item |
| `kind/tests` | Issue, PR | Additions or modifications to the project testing suite |
### `needs/`
Actions or missing requirements needed by the issue or pull request.
| Label | Applies to | Description |
| --------------------------- | ---------- | ----------------------------------------------------- |
| `needs/assignee` | Issue, PR | Needs an assignee |
| `needs/code-review` | PR | Needs review of code |
| `needs/design-review` | Issue, PR | Needs review of design |
| `needs/docs-review` | Issue, PR | Needs review by the documentation team |
| `needs/docs-update` | Issue, PR | Needs an update to the docs |
| `needs/follow-on-work` | Issue, PR | Needs follow-on work/PR |
| `needs/issue` | PR | Needs an issue |
| `needs/maintainer-decision` | Issue, PR | Needs maintainer discussion/decision before advancing |
| `needs/milestone` | Issue, PR | Needs milestone assignment |
| `needs/more-info` | Any | Needs more information from the author |
| `needs/more-investigation` | Issue, PR | Needs further investigation |
| `needs/priority` | Issue, PR | Needs priority assignment |
| `needs/pull-request` | Issue | Needs a pull request |
| `needs/rebase` | PR | Needs rebase to target branch |
| `needs/reproduction` | Issue, PR | Needs reproduction steps |
### `priority/`
Level of urgency of a `kind/bug` issue or pull request.
| Label | Applies to | Description |
| ------------- | ---------- | ----------------------------------------------------------------------- |
| `priority/P0` | Issue, PR | Urgent: Security, critical bugs, blocking issues. |
| `priority/P1` | Issue, PR | Important: This is a top priority and a must-have for the next release. |
| `priority/P2` | Issue, PR | Normal: Default priority |
### `status/`
Current lifecycle state of the issue or pull request.
| Label | Applies to | Description |
| --------------------- | ---------- | ---------------------------------------------------------------------- |
| `status/accepted` | Issue, PR | The issue has been reviewed and accepted for implementation |
| `status/active` | PR | The PR is actively being worked on by a maintainer or community member |
| `status/blocked` | Issue, PR | The issue/PR is blocked from advancing to another status |
| `status/do-not-merge` | PR | Should not be merged pending further review or changes |
| `status/transfer` | Any | Transferred to another project |
| `status/triage` | Any | The item needs to be sorted by maintainers |
| `status/wontfix` | Issue, PR | The issue/PR will not be fixed or addressed as described |
## Types of releases
This project has feature releases, patch releases, and security releases.
### Feature releases
Feature releases are made from the development branch, followed by cutting a release branch for future patch releases, which may also occur during the code freeze period.
#### Release Candidates
Users can expect 2-3 release candidate (RC) test releases prior to a feature release. The first RC is typically released about one to two weeks before the final release.
#### Support Policy
Once a new feature release is cut, support for the previous feature release is discontinued. An exception may be made for urgent security releases that occur shortly after a new feature release. Buildx does not offer LTS (Long-Term Support) releases.
#### Contributing to Releases
Anyone can request that an issue or PR be included in the next feature or patch release milestone, provided it meets the necessary requirements.
### Patch releases
Patch releases should only include the most critical patches. Stability is vital, so everyone should always use the latest patch release.
If a fix is needed but does not qualify for a patch release because of its code size or other criteria that make it too unpredictable, we will prioritize cutting a new feature release sooner rather than making an exception for backporting.
Following PRs are included in patch releases
- `priority/P0` fixes
- `priority/P1` fixes, assuming maintainers dont object because of the patch size
- `priority/P2` fixes, only if (both required)
- proposed by maintainer
- the patch is trivial and self-contained
- Documentation-only patches
- Vendored dependency updates, only if:
- Fixing (qualifying) bug or security issue in Buildx
- The patch is small, else a forked version of the dependency with only the patches required
New features do not qualify for patch release.
## Milestones
Milestones are used to help identify what releases a contribution will be in.
- The `v0.next` milestone collects unblocked items planned for the next 2-3 feature releases but not yet assigned to a specific version milestone.
- The `v0.backlog` milestone gathers all triaged items considered for the long-term (beyond the next 3 feature releases) or currently unfit for a future release due to certain conditions. These items may be blocked and need to be unblocked before progressing.
## Triage process
Triage provides an important way to contribute to an open-source project. When submitted without an issue this process applies to Pull Requests as well. Triage helps ensure work items are resolved quickly by:
- Ensuring the issue's intent and purpose are described precisely. This is necessary because it can be difficult for an issue to explain how an end user experiences a problem and what actions they took to arrive at the problem.
- Giving a contributor the information they need before they commit to resolving an issue.
- Lowering the issue count by preventing duplicate issues.
- Streamlining the development process by preventing duplicate discussions.
If you don't have time to code, consider helping with triage. The community will thank you for saving them time by spending some of yours. The same basic process should be applied upon receipt of a new issue.
1. Verify essential information
2. Classify the issue
3. Prioritizing the issue
### Verify essential information
Before advancing the triage process, ensure the issue contains all necessary information to be properly understood and assessed. The required information may vary by issue type, but typically includes the system environment, version numbers, reproduction steps, expected outcomes, and actual results.
- **Exercising Judgment**: Use your best judgment to assess the issue descriptions completeness.
- **Communicating Needs**: If the information provided is insufficient, kindly request additional details from the author. Explain that this information is crucial for clarity and resolution of the issue, and apply the `needs/more-information` label to indicate a response from the author is required.
### Classify the issue
An issue will typically have multiple labels. These are used to help communicate key information about context, requirements, and status. At a minimum, a properly classified issue should have:
- (Required) One or more [`area/*`](#area) labels
- (Required) One [`kind/*`](#kind) label to indicate the type of issue
- (Required if `kind/bug`) A [`priority/*`](#priority) label
When assigning a decision the following labels should be present:
- (Required) One [`status/*`](#status) label to indicate lifecycle status
Additional labels can provide more clarity:
- Zero or more [`needs/*`](#needs) labels to indicate missing items
- Zero or more [`impact/*`](#impact) labels
- One [`exp/*`](#exp) label
## Prioritization guidelines for `kind/bug`
When an issue or pull request of `kind/bug` is correctly categorized and attached to a milestone, the labels indicate the urgency with which it should be completed.
**priority/P0**
Fixing this item is the highest priority. A patch release will follow as soon as a patch is available and verified. This level is used exclusively for bugs.
Examples:
- Regression in a critical code path
- Panic in a critical code path
- Corruption in critical code path or rest of the system
- Leaked zero-day critical security
**priority/P1**
Items with this label should be fixed with high priority and almost always included in a patch release. Unless waiting for another issue, patch releases should happen within a week. This level is not used for features or enhancements.
Examples:
- Any regression, panic
- Measurable performance regression
- A major bug in a new feature in the latest release
- Incompatibility with upgraded external dependency
**priority/P2**
This is the default priority and is implied in the absence of a `priority/` label. Bugs with this priority should be included in the next feature release but may land in a patch release if they are ready and unlikely to impact other functionality adversely. Non-bug issues with this priority should also be included in the next feature release if they are available and ready.
Examples:
- Confirmed bugs
- Bugs in non-default configurations
- Most enhancements
## Issue lifecyle
```mermaid
flowchart LR
create([New issue]) --> triage
subgraph triage[Triage Loop]
review[Review]
end
subgraph decision[Decision]
accept[Accept]
close[Close]
end
triage -- if accepted --> accept[Assign status, milestone]
triage -- if rejected --> close[Assign status, close issue]
```
### Examples
#### Submitting a bug
To help illustrate the issue life cycle lets walk through submitting an issue as a potential bug in CI that enters a feedback loop and is eventually accepted as P2 priority and placed on the backlog.
```mermaid
flowchart LR
new([New issue])
subgraph triage[Triage]
direction LR
create["Action: Submit issue via Bug form\nLabels: kind/maybe-bug, status/triage"]
style create text-align:left
subgraph review[Review]
direction TB
classify["Action: Maintainer reviews issue, requests more info\nLabels: kind/maybe-bug, status/triage, needs/more-info, area/*"]
style classify text-align:left
update["Action: Author updates issue\nLabels: kind/maybe-bug, status/triage, needs/more-info, area/*"]
style update text-align:left
classify --> update
update --> classify
end
create --> review
end
subgraph decision[Decision]
accept["Action: Maintainer reviews updates, accepts, assigns milestone\nLabels: kind/bug, priority/P2, status/accepted, area/*, impact/*"]
style accept text-align: left
end
new --> triage
triage --> decision
```
## Pull request review process
A thorough and timely review process for pull requests (PRs) is crucial for maintaining the integrity and quality of the project while fostering a collaborative environment.
- **Labeling**: Most labels should be inherited from a linked issue. If no issue is linked an extended review process may be required.
- **Continuous Integration**: With few exceptions, it is crucial that all Continuous Integration (CI) workflows pass successfully.
- **Draft Status**: Incomplete or long-running PRs should be placed in "Draft" status. They may revert to "Draft" status upon initial review if significant rework is required.
```mermaid
flowchart LR
triage([Triage])
draft[Draft PR]
review[PR Review]
closed{{Close PR}}
merge{{Merge PR}}
subgraph feedback1[Feedback Loop]
draft
end
subgraph feedback2[Feedback Loop]
review
end
triage --> draft
draft --> review
review --> closed
review --> draft
review --> merge
```
## Handling stalled issues and pull requests
Unfortunately, some issues or pull requests can remain inactive for extended periods. To mitigate this, automation is employed to prompt both the author and maintainers, ensuring that all contributions receive appropriate attention.
**For Authors:**
- **Closure of Inactive Items**: If your issue or PR becomes irrelevant or is no longer needed, please close it to help keep the project clean.
- **Prompt Responses**: If additional information is requested, please respond promptly to facilitate progress.
**For Maintainers:**
- **Timely Responses**: Endeavor to address issues and PRs within a reasonable timeframe to keep the community actively engaged.
- **Engagement with Stale Issues**: If an issue becomes stale due to maintainer inaction, re-engage with the author to reassess and revitalize the discussion.
**Stale and Rotten Policy:**
- An issue or PR will be labeled as **`stale`** after 14 calendar days of inactivity. If it remains inactive for another 30 days, it will be labeled as **`rotten`** and closed.
- Authors whose issues or PRs have been closed are welcome to re-open them or create new ones and link to the original.
**Skipping Stale Processing:**
- To prevent an issue or PR from being marked as stale, label it as **`frozen`**.
**Exceptions to Stale Processing:**
- Issues or PRs marked as **`frozen`**.
- Issues or PRs assigned to a milestone.
## Moving to a discussion
Sometimes, an issue or pull request may not be the appropriate medium for what is essentially a discussion. In such cases, the issue or PR will either be converted to a discussion or a new discussion will be created. The original item will then be labeled appropriately (**`kind/discussion`** or **`kind/question`**) and closed.
If you believe this conversion was made in error, please express your concerns in the new discussion thread. If necessary, a reversal to the original issue or PR format can be facilitated.
## Workflow automation
To help expedite common operations, avoid errors and reduce toil some workflow automation is used by the project. This can include:
- Stale issue or pull request processing
- Auto-labeling actions
- Auto-response actions
- Label carry over from issue to pull request
### Exempting an issue/PR from stale bot processing
The stale item handling is configured in the [repository](link-to-config-file). To exempt an issue or PR from stale processing you can:
- Add the item to a milestone
- Add the `frozen` label to the item
## Updating dependencies
- **Runtime Dependencies**: Use the latest stable release available when the first Release Candidate (RC) of a new feature release is cut. For patch releases, update to the latest corresponding patch release of the dependency.
- **Other Dependencies**: Always permitted to update to the latest patch release in the development branch. Updates to a new feature release require justification, unless the dependency is outdated. Prefer tagged versions of dependencies unless a specific untagged commit is needed. Go modules should specify the lowest compatible version; there is no requirement to update all dependencies to their latest versions before cutting a new Buildx feature release.
- **Patch Releases**: Vendored dependency updates are considered for patch releases, except in the rare cases specified previously.
- **Security Considerations**: A security scanner report indicating a non-exploitable issue via Buildx does not justify backports.

View File

@@ -7,6 +7,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"slices"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@@ -480,7 +481,7 @@ func (c Config) loadLinks(name string, t *Target, m map[string]*Target, o map[st
for _, v := range t.Contexts { for _, v := range t.Contexts {
if strings.HasPrefix(v, "target:") { if strings.HasPrefix(v, "target:") {
target := strings.TrimPrefix(v, "target:") target := strings.TrimPrefix(v, "target:")
if target == t.Name { if target == name {
return errors.Errorf("target %s cannot link to itself", target) return errors.Errorf("target %s cannot link to itself", target)
} }
for _, v := range visited { for _, v := range visited {
@@ -502,6 +503,14 @@ func (c Config) loadLinks(name string, t *Target, m map[string]*Target, o map[st
if err := c.loadLinks(target, t2, m, o, visited); err != nil { if err := c.loadLinks(target, t2, m, o, visited); err != nil {
return err return err
} }
// entitlements are inherited from linked targets
for _, ent := range t2.Entitlements {
if !slices.Contains(t.Entitlements, ent) {
t.Entitlements = append(t.Entitlements, ent)
}
}
if len(t.Platforms) > 1 && len(t2.Platforms) > 1 { if len(t.Platforms) > 1 && len(t2.Platforms) > 1 {
if !sliceEqual(t.Platforms, t2.Platforms) { if !sliceEqual(t.Platforms, t2.Platforms) {
return errors.Errorf("target %s can't be used by %s because it is defined for different platforms %v and %v", target, name, t2.Platforms, t.Platforms) return errors.Errorf("target %s can't be used by %s because it is defined for different platforms %v and %v", target, name, t2.Platforms, t.Platforms)
@@ -704,7 +713,7 @@ type Target struct {
Outputs []string `json:"output,omitempty" hcl:"output,optional" cty:"output"` Outputs []string `json:"output,omitempty" hcl:"output,optional" cty:"output"`
Pull *bool `json:"pull,omitempty" hcl:"pull,optional" cty:"pull"` Pull *bool `json:"pull,omitempty" hcl:"pull,optional" cty:"pull"`
NoCache *bool `json:"no-cache,omitempty" hcl:"no-cache,optional" cty:"no-cache"` NoCache *bool `json:"no-cache,omitempty" hcl:"no-cache,optional" cty:"no-cache"`
NetworkMode *string `json:"network" hcl:"network" cty:"network"` NetworkMode *string `json:"network,omitempty" hcl:"network,optional" cty:"network"`
NoCacheFilter []string `json:"no-cache-filter,omitempty" hcl:"no-cache-filter,optional" cty:"no-cache-filter"` NoCacheFilter []string `json:"no-cache-filter,omitempty" hcl:"no-cache-filter,optional" cty:"no-cache-filter"`
ShmSize *string `json:"shm-size,omitempty" hcl:"shm-size,optional"` ShmSize *string `json:"shm-size,omitempty" hcl:"shm-size,optional"`
Ulimits []string `json:"ulimits,omitempty" hcl:"ulimits,optional"` Ulimits []string `json:"ulimits,omitempty" hcl:"ulimits,optional"`

View File

@@ -56,7 +56,7 @@ func formatHCLError(err error, files []File) error {
break break
} }
} }
src := errdefs.Source{ src := &errdefs.Source{
Info: &pb.SourceInfo{ Info: &pb.SourceInfo{
Filename: d.Subject.Filename, Filename: d.Subject.Filename,
Data: dt, Data: dt,
@@ -72,7 +72,7 @@ func formatHCLError(err error, files []File) error {
func toErrRange(in *hcl.Range) *pb.Range { func toErrRange(in *hcl.Range) *pb.Range {
return &pb.Range{ return &pb.Range{
Start: pb.Position{Line: int32(in.Start.Line), Character: int32(in.Start.Column)}, Start: &pb.Position{Line: int32(in.Start.Line), Character: int32(in.Start.Column)},
End: pb.Position{Line: int32(in.End.Line), Character: int32(in.End.Column)}, End: &pb.Position{Line: int32(in.End.Line), Character: int32(in.End.Column)},
} }
} }

View File

@@ -11,6 +11,7 @@ import (
controllerapi "github.com/docker/buildx/controller/pb" controllerapi "github.com/docker/buildx/controller/pb"
"github.com/docker/buildx/driver" "github.com/docker/buildx/driver"
"github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/progress"
"github.com/docker/go-units"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/frontend/dockerui" "github.com/moby/buildkit/frontend/dockerui"
@@ -19,6 +20,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
const maxBakeDefinitionSize = 2 * 1024 * 1024 // 2 MB
type Input struct { type Input struct {
State *llb.State State *llb.State
URL string URL string
@@ -106,7 +109,6 @@ func ReadRemoteFiles(ctx context.Context, nodes []builder.Node, url string, name
} }
return nil, err return nil, err
}, ch) }, ch)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -178,9 +180,9 @@ func filesFromURLRef(ctx context.Context, c gwclient.Client, ref gwclient.Refere
name := inp.URL name := inp.URL
inp.URL = "" inp.URL = ""
if len(dt) > stat.Size() { if int64(len(dt)) > stat.Size {
if stat.Size() > 1024*512 { if stat.Size > maxBakeDefinitionSize {
return nil, errors.Errorf("non-archive definition URL bigger than maximum allowed size") return nil, errors.Errorf("non-archive definition URL bigger than maximum allowed size (%s)", units.HumanSize(maxBakeDefinitionSize))
} }
dt, err = ref.ReadFile(ctx, gwclient.ReadRequest{ dt, err = ref.ReadFile(ctx, gwclient.ReadRequest{

View File

@@ -50,11 +50,12 @@ import (
fstypes "github.com/tonistiigi/fsutil/types" fstypes "github.com/tonistiigi/fsutil/types"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"google.golang.org/protobuf/proto"
) )
const ( const (
printFallbackImage = "docker/dockerfile:1.5@sha256:dbbd5e059e8a07ff7ea6233b213b36aa516b4c53c645f1817a4dd18b83cbea56" printFallbackImage = "docker/dockerfile:1.7.1@sha256:a57df69d0ea827fb7266491f2813635de6f17269be881f696fbfdf2d83dda33e"
printLintFallbackImage = "docker.io/docker/dockerfile-upstream:1.8.1@sha256:e87caa74dcb7d46cd820352bfea12591f3dba3ddc4285e19c7dcd13359f7cefd" printLintFallbackImage = "docker/dockerfile:1.8.1@sha256:e87caa74dcb7d46cd820352bfea12591f3dba3ddc4285e19c7dcd13359f7cefd"
) )
type Options struct { type Options struct {
@@ -101,6 +102,9 @@ type Inputs struct {
ContextState *llb.State ContextState *llb.State
DockerfileInline string DockerfileInline string
NamedContexts map[string]NamedContext NamedContexts map[string]NamedContext
// DockerfileMappingSrc and DockerfileMappingDst are filled in by the builder.
DockerfileMappingSrc string
DockerfileMappingDst string
} }
type NamedContext struct { type NamedContext struct {
@@ -147,11 +151,11 @@ func toRepoOnly(in string) (string, error) {
return strings.Join(out, ","), nil return strings.Join(out, ","), nil
} }
func Build(ctx context.Context, nodes []builder.Node, opt map[string]Options, docker *dockerutil.Client, configDir string, w progress.Writer) (resp map[string]*client.SolveResponse, err error) { func Build(ctx context.Context, nodes []builder.Node, opts map[string]Options, docker *dockerutil.Client, cfg *confutil.Config, w progress.Writer) (resp map[string]*client.SolveResponse, err error) {
return BuildWithResultHandler(ctx, nodes, opt, docker, configDir, w, nil) return BuildWithResultHandler(ctx, nodes, opts, docker, cfg, w, nil)
} }
func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[string]Options, docker *dockerutil.Client, configDir string, w progress.Writer, resultHandleFunc func(driverIndex int, rCtx *ResultHandle)) (resp map[string]*client.SolveResponse, err error) { func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[string]Options, docker *dockerutil.Client, cfg *confutil.Config, w progress.Writer, resultHandleFunc func(driverIndex int, rCtx *ResultHandle)) (resp map[string]*client.SolveResponse, err error) {
if len(nodes) == 0 { if len(nodes) == 0 {
return nil, errors.Errorf("driver required for build") return nil, errors.Errorf("driver required for build")
} }
@@ -169,9 +173,9 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
} }
} }
if noMobyDriver != nil && !noDefaultLoad() && noCallFunc(opt) { if noMobyDriver != nil && !noDefaultLoad() && noCallFunc(opts) {
var noOutputTargets []string var noOutputTargets []string
for name, opt := range opt { for name, opt := range opts {
if noMobyDriver.Features(ctx)[driver.DefaultLoad] { if noMobyDriver.Features(ctx)[driver.DefaultLoad] {
continue continue
} }
@@ -192,7 +196,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
} }
} }
drivers, err := resolveDrivers(ctx, nodes, opt, w) drivers, err := resolveDrivers(ctx, nodes, opts, w)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -209,7 +213,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
reqForNodes := make(map[string][]*reqForNode) reqForNodes := make(map[string][]*reqForNode)
eg, ctx := errgroup.WithContext(ctx) eg, ctx := errgroup.WithContext(ctx)
for k, opt := range opt { for k, opt := range opts {
multiDriver := len(drivers[k]) > 1 multiDriver := len(drivers[k]) > 1
hasMobyDriver := false hasMobyDriver := false
addGitAttrs, err := getGitAttributes(ctx, opt.Inputs.ContextPath, opt.Inputs.DockerfilePath) addGitAttrs, err := getGitAttributes(ctx, opt.Inputs.ContextPath, opt.Inputs.DockerfilePath)
@@ -229,11 +233,13 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
if err != nil { if err != nil {
return nil, err return nil, err
} }
so, release, err := toSolveOpt(ctx, np.Node(), multiDriver, opt, gatewayOpts, configDir, w, docker) localOpt := opt
so, release, err := toSolveOpt(ctx, np.Node(), multiDriver, &localOpt, gatewayOpts, cfg, w, docker)
opts[k] = localOpt
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := saveLocalState(so, k, opt, np.Node(), configDir); err != nil { if err := saveLocalState(so, k, opt, np.Node(), cfg); err != nil {
return nil, err return nil, err
} }
addGitAttrs(so) addGitAttrs(so)
@@ -269,7 +275,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
} }
// validate that all links between targets use same drivers // validate that all links between targets use same drivers
for name := range opt { for name := range opts {
dps := reqForNodes[name] dps := reqForNodes[name]
for i, dp := range dps { for i, dp := range dps {
so := reqForNodes[name][i].so so := reqForNodes[name][i].so
@@ -305,10 +311,10 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
var respMu sync.Mutex var respMu sync.Mutex
results := waitmap.New() results := waitmap.New()
multiTarget := len(opt) > 1 multiTarget := len(opts) > 1
childTargets := calculateChildTargets(reqForNodes, opt) childTargets := calculateChildTargets(reqForNodes, opts)
for k, opt := range opt { for k, opt := range opts {
err := func(k string) (err error) { err := func(k string) (err error) {
opt := opt opt := opt
dps := drivers[k] dps := drivers[k]
@@ -494,7 +500,9 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
resultHandle, rr, err = NewResultHandle(ctx, cc, *so, "buildx", buildFunc, ch) resultHandle, rr, err = NewResultHandle(ctx, cc, *so, "buildx", buildFunc, ch)
resultHandleFunc(dp.driverIndex, resultHandle) resultHandleFunc(dp.driverIndex, resultHandle)
} else { } else {
span, ctx := tracing.StartSpan(ctx, "build")
rr, err = c.Build(ctx, *so, "buildx", buildFunc, ch) rr, err = c.Build(ctx, *so, "buildx", buildFunc, ch)
tracing.FinishWithError(span, err)
} }
if !so.Internal && desktop.BuildBackendEnabled() && node.Driver.HistoryAPISupported(ctx) { if !so.Internal && desktop.BuildBackendEnabled() && node.Driver.HistoryAPISupported(ctx) {
if err != nil { if err != nil {
@@ -1131,7 +1139,7 @@ func ReadSourcePolicy() (*spb.Policy, error) {
var pol spb.Policy var pol spb.Policy
if err := json.Unmarshal(data, &pol); err != nil { if err := json.Unmarshal(data, &pol); err != nil {
// maybe it's in protobuf format? // maybe it's in protobuf format?
e2 := pol.Unmarshal(data) e2 := proto.Unmarshal(data, &pol)
if e2 != nil { if e2 != nil {
return nil, errors.Wrap(err, "failed to parse source policy") return nil, errors.Wrap(err, "failed to parse source policy")
} }

View File

@@ -5,12 +5,13 @@ import (
"github.com/docker/buildx/builder" "github.com/docker/buildx/builder"
"github.com/docker/buildx/localstate" "github.com/docker/buildx/localstate"
"github.com/docker/buildx/util/confutil"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
) )
func saveLocalState(so *client.SolveOpt, target string, opts Options, node builder.Node, configDir string) error { func saveLocalState(so *client.SolveOpt, target string, opts Options, node builder.Node, cfg *confutil.Config) error {
var err error var err error
if so.Ref == "" { if so.Ref == "" || opts.CallFunc != nil {
return nil return nil
} }
lp := opts.Inputs.ContextPath lp := opts.Inputs.ContextPath
@@ -30,7 +31,7 @@ func saveLocalState(so *client.SolveOpt, target string, opts Options, node build
if lp == "" && dp == "" { if lp == "" && dp == "" {
return nil return nil
} }
l, err := localstate.New(configDir) l, err := localstate.New(cfg)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -35,7 +35,7 @@ import (
"github.com/tonistiigi/fsutil" "github.com/tonistiigi/fsutil"
) )
func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Options, bopts gateway.BuildOpts, configDir string, pw progress.Writer, docker *dockerutil.Client) (_ *client.SolveOpt, release func(), err error) { func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt *Options, bopts gateway.BuildOpts, cfg *confutil.Config, pw progress.Writer, docker *dockerutil.Client) (_ *client.SolveOpt, release func(), err error) {
nodeDriver := node.Driver nodeDriver := node.Driver
defers := make([]func(), 0, 2) defers := make([]func(), 0, 2)
releaseF := func() { releaseF := func() {
@@ -263,7 +263,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
so.Exports = opt.Exports so.Exports = opt.Exports
so.Session = slices.Clone(opt.Session) so.Session = slices.Clone(opt.Session)
releaseLoad, err := loadInputs(ctx, nodeDriver, opt.Inputs, pw, &so) releaseLoad, err := loadInputs(ctx, nodeDriver, &opt.Inputs, pw, &so)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -271,7 +271,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
// add node identifier to shared key if one was specified // add node identifier to shared key if one was specified
if so.SharedKey != "" { if so.SharedKey != "" {
so.SharedKey += ":" + confutil.TryNodeIdentifier(configDir) so.SharedKey += ":" + cfg.TryNodeIdentifier()
} }
if opt.Pull { if opt.Pull {
@@ -356,7 +356,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
return &so, releaseF, nil return &so, releaseF, nil
} }
func loadInputs(ctx context.Context, d *driver.DriverHandle, 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 == "" { if inp.ContextPath == "" {
return nil, errors.New("please specify build context (e.g. \".\" for the current directory)") return nil, errors.New("please specify build context (e.g. \".\" for the current directory)")
} }
@@ -364,11 +364,12 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp Inputs, pw prog
// TODO: handle stdin, symlinks, remote contexts, check files exist // TODO: handle stdin, symlinks, remote contexts, check files exist
var ( var (
err error err error
dockerfileReader io.ReadCloser dockerfileReader io.ReadCloser
dockerfileDir string dockerfileDir string
dockerfileName = inp.DockerfilePath dockerfileName = inp.DockerfilePath
toRemove []string dockerfileSrcName = inp.DockerfilePath
toRemove []string
) )
switch { switch {
@@ -440,6 +441,11 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp Inputs, pw prog
if inp.DockerfileInline != "" { if inp.DockerfileInline != "" {
dockerfileReader = io.NopCloser(strings.NewReader(inp.DockerfileInline)) dockerfileReader = io.NopCloser(strings.NewReader(inp.DockerfileInline))
dockerfileSrcName = "inline"
} else if inp.DockerfilePath == "-" {
dockerfileSrcName = "stdin"
} else if inp.DockerfilePath == "" {
dockerfileSrcName = filepath.Join(inp.ContextPath, "Dockerfile")
} }
if dockerfileReader != nil { if dockerfileReader != nil {
@@ -540,6 +546,9 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp Inputs, pw prog
_ = os.RemoveAll(dir) _ = os.RemoveAll(dir)
} }
} }
inp.DockerfileMappingSrc = dockerfileSrcName
inp.DockerfileMappingDst = dockerfileName
return release, nil return release, nil
} }

View File

@@ -15,6 +15,7 @@ import (
controlapi "github.com/moby/buildkit/api/services/control" controlapi "github.com/moby/buildkit/api/services/control"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types" provenancetypes "github.com/moby/buildkit/solver/llbsolver/provenance/types"
digest "github.com/opencontainers/go-digest"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1" ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
@@ -124,8 +125,8 @@ func lookupProvenance(res *controlapi.BuildResultInfo) *ocispecs.Descriptor {
for _, a := range res.Attestations { for _, a := range res.Attestations {
if a.MediaType == "application/vnd.in-toto+json" && strings.HasPrefix(a.Annotations["in-toto.io/predicate-type"], "https://slsa.dev/provenance/") { if a.MediaType == "application/vnd.in-toto+json" && strings.HasPrefix(a.Annotations["in-toto.io/predicate-type"], "https://slsa.dev/provenance/") {
return &ocispecs.Descriptor{ return &ocispecs.Descriptor{
Digest: a.Digest, Digest: digest.Digest(a.Digest),
Size: a.Size_, Size: a.Size,
MediaType: a.MediaType, MediaType: a.MediaType,
Annotations: a.Annotations, Annotations: a.Annotations,
} }

View File

@@ -295,14 +295,14 @@ func (r *ResultHandle) build(buildFunc gateway.BuildFunc) (err error) {
func (r *ResultHandle) getContainerConfig(cfg *controllerapi.InvokeConfig) (containerCfg gateway.NewContainerRequest, _ error) { func (r *ResultHandle) getContainerConfig(cfg *controllerapi.InvokeConfig) (containerCfg gateway.NewContainerRequest, _ error) {
if r.res != nil && r.solveErr == nil { if r.res != nil && r.solveErr == nil {
logrus.Debugf("creating container from successful build") logrus.Debugf("creating container from successful build")
ccfg, err := containerConfigFromResult(r.res, *cfg) ccfg, err := containerConfigFromResult(r.res, cfg)
if err != nil { if err != nil {
return containerCfg, err return containerCfg, err
} }
containerCfg = *ccfg containerCfg = *ccfg
} else { } else {
logrus.Debugf("creating container from failed build %+v", cfg) logrus.Debugf("creating container from failed build %+v", cfg)
ccfg, err := containerConfigFromError(r.solveErr, *cfg) ccfg, err := containerConfigFromError(r.solveErr, cfg)
if err != nil { if err != nil {
return containerCfg, errors.Wrapf(err, "no result nor error is available") return containerCfg, errors.Wrapf(err, "no result nor error is available")
} }
@@ -315,19 +315,19 @@ func (r *ResultHandle) getProcessConfig(cfg *controllerapi.InvokeConfig, stdin i
processCfg := newStartRequest(stdin, stdout, stderr) processCfg := newStartRequest(stdin, stdout, stderr)
if r.res != nil && r.solveErr == nil { if r.res != nil && r.solveErr == nil {
logrus.Debugf("creating container from successful build") logrus.Debugf("creating container from successful build")
if err := populateProcessConfigFromResult(&processCfg, r.res, *cfg); err != nil { if err := populateProcessConfigFromResult(&processCfg, r.res, cfg); err != nil {
return processCfg, err return processCfg, err
} }
} else { } else {
logrus.Debugf("creating container from failed build %+v", cfg) logrus.Debugf("creating container from failed build %+v", cfg)
if err := populateProcessConfigFromError(&processCfg, r.solveErr, *cfg); err != nil { if err := populateProcessConfigFromError(&processCfg, r.solveErr, cfg); err != nil {
return processCfg, err return processCfg, err
} }
} }
return processCfg, nil return processCfg, nil
} }
func containerConfigFromResult(res *gateway.Result, cfg controllerapi.InvokeConfig) (*gateway.NewContainerRequest, error) { func containerConfigFromResult(res *gateway.Result, cfg *controllerapi.InvokeConfig) (*gateway.NewContainerRequest, error) {
if cfg.Initial { if cfg.Initial {
return nil, errors.Errorf("starting from the container from the initial state of the step is supported only on the failed steps") return nil, errors.Errorf("starting from the container from the initial state of the step is supported only on the failed steps")
} }
@@ -352,7 +352,7 @@ func containerConfigFromResult(res *gateway.Result, cfg controllerapi.InvokeConf
}, nil }, nil
} }
func populateProcessConfigFromResult(req *gateway.StartRequest, res *gateway.Result, cfg controllerapi.InvokeConfig) error { func populateProcessConfigFromResult(req *gateway.StartRequest, res *gateway.Result, cfg *controllerapi.InvokeConfig) error {
imgData := res.Metadata[exptypes.ExporterImageConfigKey] imgData := res.Metadata[exptypes.ExporterImageConfigKey]
var img *specs.Image var img *specs.Image
if len(imgData) > 0 { if len(imgData) > 0 {
@@ -403,7 +403,7 @@ func populateProcessConfigFromResult(req *gateway.StartRequest, res *gateway.Res
return nil return nil
} }
func containerConfigFromError(solveErr *errdefs.SolveError, cfg controllerapi.InvokeConfig) (*gateway.NewContainerRequest, error) { func containerConfigFromError(solveErr *errdefs.SolveError, cfg *controllerapi.InvokeConfig) (*gateway.NewContainerRequest, error) {
exec, err := execOpFromError(solveErr) exec, err := execOpFromError(solveErr)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -431,7 +431,7 @@ func containerConfigFromError(solveErr *errdefs.SolveError, cfg controllerapi.In
}, nil }, nil
} }
func populateProcessConfigFromError(req *gateway.StartRequest, solveErr *errdefs.SolveError, cfg controllerapi.InvokeConfig) error { func populateProcessConfigFromError(req *gateway.StartRequest, solveErr *errdefs.SolveError, cfg *controllerapi.InvokeConfig) error {
exec, err := execOpFromError(solveErr) exec, err := execOpFromError(solveErr)
if err != nil { if err != nil {
return err return err

View File

@@ -7,12 +7,15 @@ import (
"github.com/docker/buildx/driver" "github.com/docker/buildx/driver"
"github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/progress"
"github.com/docker/go-units"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/client/llb"
gwclient "github.com/moby/buildkit/frontend/gateway/client" gwclient "github.com/moby/buildkit/frontend/gateway/client"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
const maxDockerfileSize = 2 * 1024 * 1024 // 2 MB
func createTempDockerfileFromURL(ctx context.Context, d *driver.DriverHandle, 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) c, err := driver.Boot(ctx, ctx, d, pw)
if err != nil { if err != nil {
@@ -43,8 +46,8 @@ func createTempDockerfileFromURL(ctx context.Context, d *driver.DriverHandle, ur
if err != nil { if err != nil {
return nil, err return nil, err
} }
if stat.Size() > 512*1024 { if stat.Size > maxDockerfileSize {
return nil, errors.Errorf("Dockerfile %s bigger than allowed max size", url) return nil, errors.Errorf("Dockerfile %s bigger than allowed max size (%s)", url, units.HumanSize(maxDockerfileSize))
} }
dt, err := ref.ReadFile(ctx, gwclient.ReadRequest{ dt, err := ref.ReadFile(ctx, gwclient.ReadRequest{
@@ -63,7 +66,6 @@ func createTempDockerfileFromURL(ctx context.Context, d *driver.DriverHandle, ur
out = dir out = dir
return nil, nil return nil, nil
}, ch) }, ch)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@@ -435,7 +435,16 @@ func Create(ctx context.Context, txn *store.Txn, dockerCli command.Cli, opts Cre
return nil, err return nil, err
} }
buildkitdFlags, err := parseBuildkitdFlags(opts.BuildkitdFlags, driverName, driverOpts) buildkitdConfigFile := opts.BuildkitdConfigFile
if buildkitdConfigFile == "" {
// if buildkit daemon config is not provided, check if the default one
// is available and use it
if f, ok := confutil.NewConfig(dockerCli).BuildKitConfigFile(); ok {
buildkitdConfigFile = f
}
}
buildkitdFlags, err := parseBuildkitdFlags(opts.BuildkitdFlags, driverName, driverOpts, buildkitdConfigFile)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -496,15 +505,6 @@ func Create(ctx context.Context, txn *store.Txn, dockerCli command.Cli, opts Cre
setEp = false setEp = false
} }
buildkitdConfigFile := opts.BuildkitdConfigFile
if buildkitdConfigFile == "" {
// if buildkit daemon config is not provided, check if the default one
// is available and use it
if f, ok := confutil.DefaultConfigFile(dockerCli); ok {
buildkitdConfigFile = f
}
}
if err := ng.Update(opts.NodeName, ep, opts.Platforms, setEp, opts.Append, buildkitdFlags, buildkitdConfigFile, driverOpts); err != nil { if err := ng.Update(opts.NodeName, ep, opts.Platforms, setEp, opts.Append, buildkitdFlags, buildkitdConfigFile, driverOpts); err != nil {
return nil, err return nil, err
} }
@@ -584,7 +584,7 @@ func Leave(ctx context.Context, txn *store.Txn, dockerCli command.Cli, opts Leav
return err return err
} }
ls, err := localstate.New(confutil.ConfigDir(dockerCli)) ls, err := localstate.New(confutil.NewConfig(dockerCli))
if err != nil { if err != nil {
return err return err
} }
@@ -641,7 +641,7 @@ func validateBuildkitEndpoint(ep string) (string, error) {
} }
// parseBuildkitdFlags parses buildkit flags // parseBuildkitdFlags parses buildkit flags
func parseBuildkitdFlags(inp string, driver string, driverOpts map[string]string) (res []string, err error) { func parseBuildkitdFlags(inp string, driver string, driverOpts map[string]string, buildkitdConfigFile string) (res []string, err error) {
if inp != "" { if inp != "" {
res, err = shlex.Split(inp) res, err = shlex.Split(inp)
if err != nil { if err != nil {
@@ -663,10 +663,27 @@ func parseBuildkitdFlags(inp string, driver string, driverOpts map[string]string
} }
} }
var hasNetworkHostEntitlementInConf bool
if buildkitdConfigFile != "" {
btoml, err := confutil.LoadConfigTree(buildkitdConfigFile)
if err != nil {
return nil, err
} else if btoml != nil {
if ies := btoml.GetArray("insecure-entitlements"); ies != nil {
for _, e := range ies.([]string) {
if e == "network.host" {
hasNetworkHostEntitlementInConf = true
break
}
}
}
}
}
if v, ok := driverOpts["network"]; ok && v == "host" && !hasNetworkHostEntitlement && driver == "docker-container" { if v, ok := driverOpts["network"]; ok && v == "host" && !hasNetworkHostEntitlement && driver == "docker-container" {
// always set network.host entitlement if user has set network=host // always set network.host entitlement if user has set network=host
res = append(res, "--allow-insecure-entitlement=network.host") res = append(res, "--allow-insecure-entitlement=network.host")
} else if len(allowInsecureEntitlements) == 0 && (driver == "kubernetes" || driver == "docker-container") { } else if len(allowInsecureEntitlements) == 0 && !hasNetworkHostEntitlementInConf && (driver == "kubernetes" || driver == "docker-container") {
// set network.host entitlement if user does not provide any as // set network.host entitlement if user does not provide any as
// network is isolated for container drivers. // network is isolated for container drivers.
res = append(res, "--allow-insecure-entitlement=network.host") res = append(res, "--allow-insecure-entitlement=network.host")

View File

@@ -1,6 +1,8 @@
package builder package builder
import ( import (
"os"
"path"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -27,19 +29,34 @@ func TestCsvToMap(t *testing.T) {
} }
func TestParseBuildkitdFlags(t *testing.T) { func TestParseBuildkitdFlags(t *testing.T) {
buildkitdConf := `
# debug enables additional debug logging
debug = true
# insecure-entitlements allows insecure entitlements, disabled by default.
insecure-entitlements = [ "network.host", "security.insecure" ]
[log]
# log formatter: json or text
format = "text"
`
dirConf := t.TempDir()
buildkitdConfPath := path.Join(dirConf, "buildkitd-conf.toml")
require.NoError(t, os.WriteFile(buildkitdConfPath, []byte(buildkitdConf), 0644))
testCases := []struct { testCases := []struct {
name string name string
flags string flags string
driver string driver string
driverOpts map[string]string driverOpts map[string]string
expected []string buildkitdConfigFile string
wantErr bool expected []string
wantErr bool
}{ }{
{ {
"docker-container no flags", "docker-container no flags",
"", "",
"docker-container", "docker-container",
nil, nil,
"",
[]string{ []string{
"--allow-insecure-entitlement=network.host", "--allow-insecure-entitlement=network.host",
}, },
@@ -50,6 +67,7 @@ func TestParseBuildkitdFlags(t *testing.T) {
"", "",
"kubernetes", "kubernetes",
nil, nil,
"",
[]string{ []string{
"--allow-insecure-entitlement=network.host", "--allow-insecure-entitlement=network.host",
}, },
@@ -60,6 +78,7 @@ func TestParseBuildkitdFlags(t *testing.T) {
"", "",
"remote", "remote",
nil, nil,
"",
nil, nil,
false, false,
}, },
@@ -68,6 +87,7 @@ func TestParseBuildkitdFlags(t *testing.T) {
"--allow-insecure-entitlement=security.insecure", "--allow-insecure-entitlement=security.insecure",
"docker-container", "docker-container",
nil, nil,
"",
[]string{ []string{
"--allow-insecure-entitlement=security.insecure", "--allow-insecure-entitlement=security.insecure",
}, },
@@ -78,6 +98,7 @@ func TestParseBuildkitdFlags(t *testing.T) {
"--allow-insecure-entitlement=network.host --allow-insecure-entitlement=security.insecure", "--allow-insecure-entitlement=network.host --allow-insecure-entitlement=security.insecure",
"docker-container", "docker-container",
nil, nil,
"",
[]string{ []string{
"--allow-insecure-entitlement=network.host", "--allow-insecure-entitlement=network.host",
"--allow-insecure-entitlement=security.insecure", "--allow-insecure-entitlement=security.insecure",
@@ -89,6 +110,7 @@ func TestParseBuildkitdFlags(t *testing.T) {
"", "",
"docker-container", "docker-container",
map[string]string{"network": "host"}, map[string]string{"network": "host"},
"",
[]string{ []string{
"--allow-insecure-entitlement=network.host", "--allow-insecure-entitlement=network.host",
}, },
@@ -99,6 +121,7 @@ func TestParseBuildkitdFlags(t *testing.T) {
"--allow-insecure-entitlement=network.host", "--allow-insecure-entitlement=network.host",
"docker-container", "docker-container",
map[string]string{"network": "host"}, map[string]string{"network": "host"},
"",
[]string{ []string{
"--allow-insecure-entitlement=network.host", "--allow-insecure-entitlement=network.host",
}, },
@@ -109,17 +132,28 @@ func TestParseBuildkitdFlags(t *testing.T) {
"--allow-insecure-entitlement=network.host --allow-insecure-entitlement=security.insecure", "--allow-insecure-entitlement=network.host --allow-insecure-entitlement=security.insecure",
"docker-container", "docker-container",
map[string]string{"network": "host"}, map[string]string{"network": "host"},
"",
[]string{ []string{
"--allow-insecure-entitlement=network.host", "--allow-insecure-entitlement=network.host",
"--allow-insecure-entitlement=security.insecure", "--allow-insecure-entitlement=security.insecure",
}, },
false, false,
}, },
{
"docker-container with buildkitd conf setting network.host entitlement",
"",
"docker-container",
nil,
buildkitdConfPath,
nil,
false,
},
{ {
"error parsing flags", "error parsing flags",
"foo'", "foo'",
"docker-container", "docker-container",
nil, nil,
"",
nil, nil,
true, true,
}, },
@@ -127,7 +161,7 @@ func TestParseBuildkitdFlags(t *testing.T) {
for _, tt := range testCases { for _, tt := range testCases {
tt := tt tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
flags, err := parseBuildkitdFlags(tt.flags, tt.driver, tt.driverOpts) flags, err := parseBuildkitdFlags(tt.flags, tt.driver, tt.driverOpts, tt.buildkitdConfigFile)
if tt.wantErr { if tt.wantErr {
require.Error(t, err) require.Error(t, err)
return return

75
cmd/buildx/debug.go Normal file
View File

@@ -0,0 +1,75 @@
package main
import (
"context"
"os"
"runtime"
"runtime/pprof"
"github.com/moby/buildkit/util/bklog"
"github.com/sirupsen/logrus"
)
func setupDebugProfiles(ctx context.Context) (stop func()) {
var stopFuncs []func()
if fn := setupCPUProfile(ctx); fn != nil {
stopFuncs = append(stopFuncs, fn)
}
if fn := setupHeapProfile(ctx); fn != nil {
stopFuncs = append(stopFuncs, fn)
}
return func() {
for _, fn := range stopFuncs {
fn()
}
}
}
func setupCPUProfile(ctx context.Context) (stop func()) {
if cpuProfile := os.Getenv("BUILDX_CPU_PROFILE"); cpuProfile != "" {
f, err := os.Create(cpuProfile)
if err != nil {
bklog.G(ctx).Warn("could not create cpu profile", logrus.WithError(err))
return nil
}
if err := pprof.StartCPUProfile(f); err != nil {
bklog.G(ctx).Warn("could not start cpu profile", logrus.WithError(err))
_ = f.Close()
return nil
}
return func() {
pprof.StopCPUProfile()
if err := f.Close(); err != nil {
bklog.G(ctx).Warn("could not close file for cpu profile", logrus.WithError(err))
}
}
}
return nil
}
func setupHeapProfile(ctx context.Context) (stop func()) {
if heapProfile := os.Getenv("BUILDX_MEM_PROFILE"); heapProfile != "" {
// Memory profile is only created on stop.
return func() {
f, err := os.Create(heapProfile)
if err != nil {
bklog.G(ctx).Warn("could not create memory profile", logrus.WithError(err))
return
}
// get up-to-date statistics
runtime.GC()
if err := pprof.WriteHeapProfile(f); err != nil {
bklog.G(ctx).Warn("could not write memory profile", logrus.WithError(err))
}
if err := f.Close(); err != nil {
bklog.G(ctx).Warn("could not close file for memory profile", logrus.WithError(err))
}
}
}
return nil
}

View File

@@ -6,6 +6,7 @@ import (
"os" "os"
"github.com/docker/buildx/commands" "github.com/docker/buildx/commands"
controllererrors "github.com/docker/buildx/controller/errdefs"
"github.com/docker/buildx/util/desktop" "github.com/docker/buildx/util/desktop"
"github.com/docker/buildx/version" "github.com/docker/buildx/version"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
@@ -16,6 +17,7 @@ import (
cliflags "github.com/docker/cli/cli/flags" cliflags "github.com/docker/cli/cli/flags"
"github.com/moby/buildkit/solver/errdefs" "github.com/moby/buildkit/solver/errdefs"
"github.com/moby/buildkit/util/stack" "github.com/moby/buildkit/util/stack"
"github.com/pkg/errors"
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel"
//nolint:staticcheck // vendored dependencies may still use this //nolint:staticcheck // vendored dependencies may still use this
@@ -27,6 +29,9 @@ import (
_ "github.com/docker/buildx/driver/docker-container" _ "github.com/docker/buildx/driver/docker-container"
_ "github.com/docker/buildx/driver/kubernetes" _ "github.com/docker/buildx/driver/kubernetes"
_ "github.com/docker/buildx/driver/remote" _ "github.com/docker/buildx/driver/remote"
// Use custom grpc codec to utilize vtprotobuf
_ "github.com/moby/buildkit/util/grpcutil/encoding/proto"
) )
func init() { func init() {
@@ -70,6 +75,16 @@ func runPlugin(cmd *command.DockerCli) error {
}) })
} }
func run(cmd *command.DockerCli) error {
stopProfiles := setupDebugProfiles(context.TODO())
defer stopProfiles()
if plugin.RunningStandalone() {
return runStandalone(cmd)
}
return runPlugin(cmd)
}
func main() { func main() {
cmd, err := command.NewDockerCli() cmd, err := command.NewDockerCli()
if err != nil { if err != nil {
@@ -77,15 +92,11 @@ func main() {
os.Exit(1) os.Exit(1)
} }
if plugin.RunningStandalone() { if err = run(cmd); err == nil {
err = runStandalone(cmd)
} else {
err = runPlugin(cmd)
}
if err == nil {
return return
} }
// Check the error from the run function above.
if sterr, ok := err.(cli.StatusError); ok { if sterr, ok := err.(cli.StatusError); ok {
if sterr.Status != "" { if sterr.Status != "" {
fmt.Fprintln(cmd.Err(), sterr.Status) fmt.Fprintln(cmd.Err(), sterr.Status)
@@ -106,8 +117,15 @@ func main() {
} else { } else {
fmt.Fprintf(cmd.Err(), "ERROR: %v\n", err) fmt.Fprintf(cmd.Err(), "ERROR: %v\n", err)
} }
if ebr, ok := err.(*desktop.ErrorWithBuildRef); ok {
var ebr *desktop.ErrorWithBuildRef
if errors.As(err, &ebr) {
ebr.Print(cmd.Err()) ebr.Print(cmd.Err())
} else {
var be *controllererrors.BuildError
if errors.As(err, &be) {
be.PrintBuildDetails(cmd.Err())
}
} }
os.Exit(1) os.Exit(1)

View File

@@ -265,7 +265,7 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
} }
done := timeBuildCommand(mp, attributes) done := timeBuildCommand(mp, attributes)
resp, retErr := build.Build(ctx, nodes, bo, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), printer) resp, retErr := build.Build(ctx, nodes, bo, dockerutil.NewClient(dockerCli), confutil.NewConfig(dockerCli), printer)
if err := printer.Wait(); retErr == nil { if err := printer.Wait(); retErr == nil {
retErr = err retErr = err
} }
@@ -335,7 +335,7 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
if callFormatJSON { if callFormatJSON {
jsonResults[name] = map[string]any{} jsonResults[name] = map[string]any{}
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
if code, err := printResult(buf, pf, res); err != nil { if code, err := printResult(buf, pf, res, name, &req.Inputs); err != nil {
jsonResults[name]["error"] = err.Error() jsonResults[name]["error"] = err.Error()
exitCode = 1 exitCode = 1
} else if code != 0 && exitCode == 0 { } else if code != 0 && exitCode == 0 {
@@ -361,7 +361,7 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
} }
fmt.Fprintln(dockerCli.Out()) fmt.Fprintln(dockerCli.Out())
if code, err := printResult(dockerCli.Out(), pf, res); err != nil { if code, err := printResult(dockerCli.Out(), pf, res, name, &req.Inputs); err != nil {
fmt.Fprintf(dockerCli.Out(), "error: %v\n", err) fmt.Fprintf(dockerCli.Out(), "error: %v\n", err)
exitCode = 1 exitCode = 1
} else if code != 0 && exitCode == 0 { } else if code != 0 && exitCode == 0 {
@@ -464,13 +464,19 @@ func saveLocalStateGroup(dockerCli command.Cli, in bakeOptions, targets []string
groupRef := identity.NewID() groupRef := identity.NewID()
refs := make([]string, 0, len(bo)) refs := make([]string, 0, len(bo))
for k, b := range bo { for k, b := range bo {
if b.CallFunc != nil {
continue
}
b.Ref = identity.NewID() b.Ref = identity.NewID()
b.GroupRef = groupRef b.GroupRef = groupRef
b.ProvenanceResponseMode = prm b.ProvenanceResponseMode = prm
refs = append(refs, b.Ref) refs = append(refs, b.Ref)
bo[k] = b bo[k] = b
} }
l, err := localstate.New(confutil.ConfigDir(dockerCli)) if len(refs) == 0 {
return nil
}
l, err := localstate.New(confutil.NewConfig(dockerCli))
if err != nil { if err != nil {
return err return err
} }
@@ -621,7 +627,7 @@ func bakeMetricAttributes(dockerCli command.Cli, driverType, url, cmdContext str
commandNameAttribute.String("bake"), commandNameAttribute.String("bake"),
attribute.Stringer(string(commandOptionsHash), &bakeOptionsHash{ attribute.Stringer(string(commandOptionsHash), &bakeOptionsHash{
bakeOptions: options, bakeOptions: options,
configDir: confutil.ConfigDir(dockerCli), cfg: confutil.NewConfig(dockerCli),
url: url, url: url,
cmdContext: cmdContext, cmdContext: cmdContext,
targets: targets, targets: targets,
@@ -633,7 +639,7 @@ func bakeMetricAttributes(dockerCli command.Cli, driverType, url, cmdContext str
type bakeOptionsHash struct { type bakeOptionsHash struct {
*bakeOptions *bakeOptions
configDir string cfg *confutil.Config
url string url string
cmdContext string cmdContext string
targets []string targets []string
@@ -657,7 +663,7 @@ func (o *bakeOptionsHash) String() string {
joinedFiles := strings.Join(files, ",") joinedFiles := strings.Join(files, ",")
joinedTargets := strings.Join(targets, ",") joinedTargets := strings.Join(targets, ",")
salt := confutil.TryNodeIdentifier(o.configDir) salt := o.cfg.TryNodeIdentifier()
h := sha256.New() h := sha256.New()
for _, s := range []string{url, cmdContext, joinedFiles, joinedTargets, salt} { for _, s := range []string{url, cmdContext, joinedFiles, joinedTargets, salt} {

View File

@@ -49,6 +49,7 @@ import (
"github.com/moby/buildkit/frontend/subrequests/outline" "github.com/moby/buildkit/frontend/subrequests/outline"
"github.com/moby/buildkit/frontend/subrequests/targets" "github.com/moby/buildkit/frontend/subrequests/targets"
"github.com/moby/buildkit/solver/errdefs" "github.com/moby/buildkit/solver/errdefs"
solverpb "github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/grpcerrors" "github.com/moby/buildkit/util/grpcerrors"
"github.com/moby/buildkit/util/progress/progressui" "github.com/moby/buildkit/util/progress/progressui"
"github.com/morikuni/aec" "github.com/morikuni/aec"
@@ -60,6 +61,7 @@ import (
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/protobuf/proto"
) )
type buildOptions struct { type buildOptions struct {
@@ -236,7 +238,7 @@ func buildMetricAttributes(dockerCli command.Cli, driverType string, options *bu
commandNameAttribute.String("build"), commandNameAttribute.String("build"),
attribute.Stringer(string(commandOptionsHash), &buildOptionsHash{ attribute.Stringer(string(commandOptionsHash), &buildOptionsHash{
buildOptions: options, buildOptions: options,
configDir: confutil.ConfigDir(dockerCli), cfg: confutil.NewConfig(dockerCli),
}), }),
driverNameAttribute.String(options.builder), driverNameAttribute.String(options.builder),
driverTypeAttribute.String(driverType), driverTypeAttribute.String(driverType),
@@ -248,7 +250,7 @@ func buildMetricAttributes(dockerCli command.Cli, driverType string, options *bu
// the fmt.Stringer interface. // the fmt.Stringer interface.
type buildOptionsHash struct { type buildOptionsHash struct {
*buildOptions *buildOptions
configDir string cfg *confutil.Config
result string result string
resultOnce sync.Once resultOnce sync.Once
} }
@@ -265,7 +267,7 @@ func (o *buildOptionsHash) String() string {
if contextPath != "-" && osutil.IsLocalDir(contextPath) { if contextPath != "-" && osutil.IsLocalDir(contextPath) {
contextPath = osutil.ToAbs(contextPath) contextPath = osutil.ToAbs(contextPath)
} }
salt := confutil.TryNodeIdentifier(o.configDir) salt := o.cfg.TryNodeIdentifier()
h := sha256.New() h := sha256.New()
for _, s := range []string{target, contextPath, dockerfile, salt} { for _, s := range []string{target, contextPath, dockerfile, salt} {
@@ -346,11 +348,12 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
done := timeBuildCommand(mp, attributes) done := timeBuildCommand(mp, attributes)
var resp *client.SolveResponse var resp *client.SolveResponse
var inputs *build.Inputs
var retErr error var retErr error
if confutil.IsExperimental() { if confutil.IsExperimental() {
resp, retErr = runControllerBuild(ctx, dockerCli, opts, options, printer) resp, inputs, retErr = runControllerBuild(ctx, dockerCli, opts, options, printer)
} else { } else {
resp, retErr = runBasicBuild(ctx, dockerCli, opts, printer) resp, inputs, retErr = runBasicBuild(ctx, dockerCli, opts, printer)
} }
if err := printer.Wait(); retErr == nil { if err := printer.Wait(); retErr == nil {
@@ -387,7 +390,7 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions)
} }
} }
if opts.CallFunc != nil { if opts.CallFunc != nil {
if exitcode, err := printResult(dockerCli.Out(), opts.CallFunc, resp.ExporterResponse); err != nil { if exitcode, err := printResult(dockerCli.Out(), opts.CallFunc, resp.ExporterResponse, options.target, inputs); err != nil {
return err return err
} else if exitcode != 0 { } else if exitcode != 0 {
os.Exit(exitcode) os.Exit(exitcode)
@@ -405,22 +408,22 @@ func getImageID(resp map[string]string) string {
return dgst return dgst
} }
func runBasicBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, printer *progress.Printer) (*client.SolveResponse, error) { func runBasicBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, printer *progress.Printer) (*client.SolveResponse, *build.Inputs, error) {
resp, res, err := cbuild.RunBuild(ctx, dockerCli, *opts, dockerCli.In(), printer, false) resp, res, dfmap, err := cbuild.RunBuild(ctx, dockerCli, opts, dockerCli.In(), printer, false)
if res != nil { if res != nil {
res.Done() res.Done()
} }
return resp, err return resp, dfmap, err
} }
func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, options buildOptions, printer *progress.Printer) (*client.SolveResponse, error) { func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, options buildOptions, printer *progress.Printer) (*client.SolveResponse, *build.Inputs, error) {
if options.invokeConfig != nil && (options.dockerfileName == "-" || options.contextPath == "-") { if options.invokeConfig != nil && (options.dockerfileName == "-" || options.contextPath == "-") {
// stdin must be usable for monitor // stdin must be usable for monitor
return nil, errors.Errorf("Dockerfile or context from stdin is not supported with invoke") return nil, nil, errors.Errorf("Dockerfile or context from stdin is not supported with invoke")
} }
c, err := controller.NewController(ctx, options.ControlOptions, dockerCli, printer) c, err := controller.NewController(ctx, options.ControlOptions, dockerCli, printer)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
defer func() { defer func() {
if err := c.Close(); err != nil { if err := c.Close(); err != nil {
@@ -432,12 +435,13 @@ func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *contro
// so we need to resolve paths to abosolute ones in the client. // so we need to resolve paths to abosolute ones in the client.
opts, err = controllerapi.ResolveOptionPaths(opts) opts, err = controllerapi.ResolveOptionPaths(opts)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
var ref string var ref string
var retErr error var retErr error
var resp *client.SolveResponse var resp *client.SolveResponse
var inputs *build.Inputs
var f *ioset.SingleForwarder var f *ioset.SingleForwarder
var pr io.ReadCloser var pr io.ReadCloser
@@ -455,7 +459,7 @@ func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *contro
}) })
} }
ref, resp, err = c.Build(ctx, *opts, pr, printer) ref, resp, inputs, err = c.Build(ctx, opts, pr, printer)
if err != nil { if err != nil {
var be *controllererrors.BuildError var be *controllererrors.BuildError
if errors.As(err, &be) { if errors.As(err, &be) {
@@ -463,7 +467,7 @@ func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *contro
retErr = err retErr = err
// We can proceed to monitor // We can proceed to monitor
} else { } else {
return nil, errors.Wrapf(err, "failed to build") return nil, nil, errors.Wrapf(err, "failed to build")
} }
} }
@@ -504,7 +508,7 @@ func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *contro
} }
} }
return resp, retErr return resp, inputs, retErr
} }
func printError(err error, printer *progress.Printer) error { func printError(err error, printer *progress.Printer) error {
@@ -882,7 +886,7 @@ func printWarnings(w io.Writer, warnings []client.VertexWarning, mode progressui
} }
} }
func printResult(w io.Writer, f *controllerapi.CallFunc, res map[string]string) (int, error) { func printResult(w io.Writer, f *controllerapi.CallFunc, res map[string]string, target string, inp *build.Inputs) (int, error) {
switch f.Name { switch f.Name {
case "outline": case "outline":
return 0, printValue(w, outline.PrintOutline, outline.SubrequestsOutlineDefinition.Version, f.Format, res) return 0, printValue(w, outline.PrintOutline, outline.SubrequestsOutlineDefinition.Version, f.Format, res)
@@ -908,8 +912,27 @@ func printResult(w io.Writer, f *controllerapi.CallFunc, res map[string]string)
} }
fmt.Fprintf(w, "Check complete, %s\n", warningCountMsg) fmt.Fprintf(w, "Check complete, %s\n", warningCountMsg)
} }
sourceInfoMap := func(sourceInfo *solverpb.SourceInfo) *solverpb.SourceInfo {
if sourceInfo == nil || inp == nil {
return sourceInfo
}
if target == "" {
target = "default"
}
err := printValue(w, printLintViolationsWrapper, lint.SubrequestLintDefinition.Version, f.Format, res) if inp.DockerfileMappingSrc != "" {
newSourceInfo := proto.Clone(sourceInfo).(*solverpb.SourceInfo)
newSourceInfo.Filename = inp.DockerfileMappingSrc
return newSourceInfo
}
return sourceInfo
}
printLintWarnings := func(dt []byte, w io.Writer) error {
return lintResults.PrintTo(w, sourceInfoMap)
}
err := printValue(w, printLintWarnings, lint.SubrequestLintDefinition.Version, f.Format, res)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@@ -924,13 +947,8 @@ func printResult(w io.Writer, f *controllerapi.CallFunc, res map[string]string)
if f.Format != "json" && len(lintResults.Warnings) > 0 { if f.Format != "json" && len(lintResults.Warnings) > 0 {
fmt.Fprintln(w) fmt.Fprintln(w)
} }
lintBuf := bytes.NewBuffer([]byte(lintResults.Error.Message + "\n")) lintBuf := bytes.NewBuffer(nil)
sourceInfo := lintResults.Sources[lintResults.Error.Location.SourceIndex] lintResults.PrintErrorTo(lintBuf, sourceInfoMap)
source := errdefs.Source{
Info: sourceInfo,
Ranges: lintResults.Error.Location.Ranges,
}
source.Print(lintBuf)
return 0, errors.New(lintBuf.String()) return 0, errors.New(lintBuf.String())
} else if len(lintResults.Warnings) == 0 && f.Format != "json" { } else if len(lintResults.Warnings) == 0 && f.Format != "json" {
fmt.Fprintln(w, "Check complete, no warnings found.") fmt.Fprintln(w, "Check complete, no warnings found.")
@@ -968,11 +986,6 @@ func printValue(w io.Writer, printer callFunc, version string, format string, re
return printer([]byte(res["result.json"]), w) return printer([]byte(res["result.json"]), w)
} }
// FIXME: remove once https://github.com/docker/buildx/pull/2672 is sorted
func printLintViolationsWrapper(dt []byte, w io.Writer) error {
return lint.PrintLintViolations(dt, w, nil)
}
type invokeConfig struct { type invokeConfig struct {
controllerapi.InvokeConfig controllerapi.InvokeConfig
onFlag string onFlag string
@@ -1000,7 +1013,7 @@ func (cfg *invokeConfig) runDebug(ctx context.Context, ref string, options *cont
return nil, errors.Errorf("failed to configure terminal: %v", err) return nil, errors.Errorf("failed to configure terminal: %v", err)
} }
defer con.Reset() defer con.Reset()
return monitor.RunMonitor(ctx, ref, options, cfg.InvokeConfig, c, stdin, stdout, stderr, progress) return monitor.RunMonitor(ctx, ref, options, &cfg.InvokeConfig, c, stdin, stdout, stderr, progress)
} }
func (cfg *invokeConfig) parseInvokeConfig(invoke, on string) error { func (cfg *invokeConfig) parseInvokeConfig(invoke, on string) error {

View File

@@ -64,7 +64,7 @@ func RootCmd(dockerCli command.Cli, children ...DebuggableCmd) *cobra.Command {
return errors.Errorf("failed to configure terminal: %v", err) return errors.Errorf("failed to configure terminal: %v", err)
} }
_, err = monitor.RunMonitor(ctx, "", nil, controllerapi.InvokeConfig{ _, err = monitor.RunMonitor(ctx, "", nil, &controllerapi.InvokeConfig{
Tty: true, Tty: true,
}, c, dockerCli.In(), os.Stdout, os.Stderr, printer) }, c, dockerCli.In(), os.Stdout, os.Stderr, printer)
con.Reset() con.Reset()

View File

@@ -10,11 +10,12 @@ type RootOptions struct {
Builder *string Builder *string
} }
func RootCmd(dockerCli command.Cli, opts RootOptions) *cobra.Command { func RootCmd(rootcmd *cobra.Command, dockerCli command.Cli, opts RootOptions) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "imagetools", Use: "imagetools",
Short: "Commands to work on images in registry", Short: "Commands to work on images in registry",
ValidArgsFunction: completion.Disable, ValidArgsFunction: completion.Disable,
RunE: rootcmd.RunE,
} }
cmd.AddCommand( cmd.AddCommand(

View File

@@ -122,8 +122,20 @@ func runInspect(ctx context.Context, dockerCli command.Cli, in inspectOptions) e
if rule.KeepDuration > 0 { if rule.KeepDuration > 0 {
fmt.Fprintf(w, "\tKeep Duration:\t%v\n", rule.KeepDuration.String()) fmt.Fprintf(w, "\tKeep Duration:\t%v\n", rule.KeepDuration.String())
} }
if rule.KeepBytes > 0 { if rule.ReservedSpace > 0 {
fmt.Fprintf(w, "\tKeep Bytes:\t%s\n", units.BytesSize(float64(rule.KeepBytes))) fmt.Fprintf(w, "\tReserved Space:\t%s\n", units.BytesSize(float64(rule.ReservedSpace)))
}
if rule.MaxUsedSpace > 0 {
fmt.Fprintf(w, "\tMax Used Space:\t%s\n", units.BytesSize(float64(rule.MaxUsedSpace)))
}
if rule.MinFreeSpace > 0 {
fmt.Fprintf(w, "\tMin Free Space:\t%s\n", units.BytesSize(float64(rule.MinFreeSpace)))
}
}
for f, dt := range nodes[i].Files {
fmt.Fprintf(w, "File#%s:\n", f)
for _, line := range strings.Split(string(dt), "\n") {
fmt.Fprintf(w, "\t> %s\n", line)
} }
} }
} }

View File

@@ -8,6 +8,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/containerd/platforms"
"github.com/docker/buildx/builder" "github.com/docker/buildx/builder"
"github.com/docker/buildx/store" "github.com/docker/buildx/store"
"github.com/docker/buildx/store/storeutil" "github.com/docker/buildx/store/storeutil"
@@ -35,7 +36,8 @@ const (
) )
type lsOptions struct { type lsOptions struct {
format string format string
noTrunc bool
} }
func runLs(ctx context.Context, dockerCli command.Cli, in lsOptions) error { func runLs(ctx context.Context, dockerCli command.Cli, in lsOptions) error {
@@ -72,7 +74,7 @@ func runLs(ctx context.Context, dockerCli command.Cli, in lsOptions) error {
return err return err
} }
if hasErrors, err := lsPrint(dockerCli, current, builders, in.format); err != nil { if hasErrors, err := lsPrint(dockerCli, current, builders, in); err != nil {
return err return err
} else if hasErrors { } else if hasErrors {
_, _ = fmt.Fprintf(dockerCli.Err(), "\n") _, _ = fmt.Fprintf(dockerCli.Err(), "\n")
@@ -107,6 +109,7 @@ func lsCmd(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags() flags := cmd.Flags()
flags.StringVar(&options.format, "format", formatter.TableFormatKey, "Format the output") flags.StringVar(&options.format, "format", formatter.TableFormatKey, "Format the output")
flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output")
// hide builder persistent flag for this command // hide builder persistent flag for this command
cobrautil.HideInheritedFlags(cmd, "builder") cobrautil.HideInheritedFlags(cmd, "builder")
@@ -114,14 +117,15 @@ func lsCmd(dockerCli command.Cli) *cobra.Command {
return cmd return cmd
} }
func lsPrint(dockerCli command.Cli, current *store.NodeGroup, builders []*builder.Builder, format string) (hasErrors bool, _ error) { func lsPrint(dockerCli command.Cli, current *store.NodeGroup, builders []*builder.Builder, in lsOptions) (hasErrors bool, _ error) {
if format == formatter.TableFormatKey { if in.format == formatter.TableFormatKey {
format = lsDefaultTableFormat in.format = lsDefaultTableFormat
} }
ctx := formatter.Context{ ctx := formatter.Context{
Output: dockerCli.Out(), Output: dockerCli.Out(),
Format: formatter.Format(format), Format: formatter.Format(in.format),
Trunc: !in.noTrunc,
} }
sort.SliceStable(builders, func(i, j int) bool { sort.SliceStable(builders, func(i, j int) bool {
@@ -138,11 +142,12 @@ func lsPrint(dockerCli command.Cli, current *store.NodeGroup, builders []*builde
render := func(format func(subContext formatter.SubContext) error) error { render := func(format func(subContext formatter.SubContext) error) error {
for _, b := range builders { for _, b := range builders {
if err := format(&lsContext{ if err := format(&lsContext{
format: ctx.Format,
trunc: ctx.Trunc,
Builder: &lsBuilder{ Builder: &lsBuilder{
Builder: b, Builder: b,
Current: b.Name == current.Name, Current: b.Name == current.Name,
}, },
format: ctx.Format,
}); err != nil { }); err != nil {
return err return err
} }
@@ -160,6 +165,7 @@ func lsPrint(dockerCli command.Cli, current *store.NodeGroup, builders []*builde
} }
if err := format(&lsContext{ if err := format(&lsContext{
format: ctx.Format, format: ctx.Format,
trunc: ctx.Trunc,
Builder: &lsBuilder{ Builder: &lsBuilder{
Builder: b, Builder: b,
Current: b.Name == current.Name, Current: b.Name == current.Name,
@@ -196,6 +202,7 @@ type lsContext struct {
Builder *lsBuilder Builder *lsBuilder
format formatter.Format format formatter.Format
trunc bool
node builder.Node node builder.Node
} }
@@ -261,7 +268,11 @@ func (c *lsContext) Platforms() string {
if c.node.Name == "" { if c.node.Name == "" {
return "" return ""
} }
return strings.Join(platformutil.FormatInGroups(c.node.Node.Platforms, c.node.Platforms), ", ") pfs := platformutil.FormatInGroups(c.node.Node.Platforms, c.node.Platforms)
if c.trunc && c.format.IsTable() {
return truncPlatforms(pfs, 4).String()
}
return strings.Join(pfs, ", ")
} }
func (c *lsContext) Error() string { func (c *lsContext) Error() string {
@@ -272,3 +283,133 @@ func (c *lsContext) Error() string {
} }
return "" return ""
} }
var truncMajorPlatforms = []string{
"linux/amd64",
"linux/arm64",
"linux/arm",
"linux/ppc64le",
"linux/s390x",
"linux/riscv64",
"linux/mips64",
}
type truncatedPlatforms struct {
res map[string][]string
input []string
max int
}
func (tp truncatedPlatforms) List() map[string][]string {
return tp.res
}
func (tp truncatedPlatforms) String() string {
var out []string
var count int
var keys []string
for k := range tp.res {
keys = append(keys, k)
}
sort.Strings(keys)
seen := make(map[string]struct{})
for _, mpf := range truncMajorPlatforms {
if tpf, ok := tp.res[mpf]; ok {
seen[mpf] = struct{}{}
if len(tpf) == 1 {
out = append(out, fmt.Sprintf("%s", tpf[0]))
count++
} else {
hasPreferredPlatform := false
for _, pf := range tpf {
if strings.HasSuffix(pf, "*") {
hasPreferredPlatform = true
break
}
}
mainpf := mpf
if hasPreferredPlatform {
mainpf += "*"
}
out = append(out, fmt.Sprintf("%s (+%d)", mainpf, len(tpf)))
count += len(tpf)
}
}
}
for _, mpf := range keys {
if len(out) >= tp.max {
break
}
if _, ok := seen[mpf]; ok {
continue
}
if len(tp.res[mpf]) == 1 {
out = append(out, fmt.Sprintf("%s", tp.res[mpf][0]))
count++
} else {
hasPreferredPlatform := false
for _, pf := range tp.res[mpf] {
if strings.HasSuffix(pf, "*") {
hasPreferredPlatform = true
break
}
}
mainpf := mpf
if hasPreferredPlatform {
mainpf += "*"
}
out = append(out, fmt.Sprintf("%s (+%d)", mainpf, len(tp.res[mpf])))
count += len(tp.res[mpf])
}
}
left := len(tp.input) - count
if left > 0 {
out = append(out, fmt.Sprintf("(%d more)", left))
}
return strings.Join(out, ", ")
}
func truncPlatforms(pfs []string, max int) truncatedPlatforms {
res := make(map[string][]string)
for _, mpf := range truncMajorPlatforms {
for _, pf := range pfs {
if len(res) >= max {
break
}
pp, err := platforms.Parse(strings.TrimSuffix(pf, "*"))
if err != nil {
continue
}
if pp.OS+"/"+pp.Architecture == mpf {
res[mpf] = append(res[mpf], pf)
}
}
}
left := make(map[string][]string)
for _, pf := range pfs {
if len(res) >= max {
break
}
pp, err := platforms.Parse(strings.TrimSuffix(pf, "*"))
if err != nil {
continue
}
ppf := strings.TrimSuffix(pp.OS+"/"+pp.Architecture, "*")
if _, ok := res[ppf]; !ok {
left[ppf] = append(left[ppf], pf)
}
}
for k, v := range left {
res[k] = v
}
return truncatedPlatforms{
res: res,
input: pfs,
max: max,
}
}

174
commands/ls_test.go Normal file
View File

@@ -0,0 +1,174 @@
package commands
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestTruncPlatforms(t *testing.T) {
tests := []struct {
name string
platforms []string
max int
expectedList map[string][]string
expectedOut string
}{
{
name: "arm64 preferred and emulated",
platforms: []string{"linux/arm64*", "linux/amd64", "linux/amd64/v2", "linux/riscv64", "linux/ppc64le", "linux/s390x", "linux/386", "linux/mips64le", "linux/mips64", "linux/arm/v7", "linux/arm/v6"},
max: 4,
expectedList: map[string][]string{
"linux/amd64": {
"linux/amd64",
"linux/amd64/v2",
},
"linux/arm": {
"linux/arm/v7",
"linux/arm/v6",
},
"linux/arm64": {
"linux/arm64*",
},
"linux/ppc64le": {
"linux/ppc64le",
},
},
expectedOut: "linux/amd64 (+2), linux/arm64*, linux/arm (+2), linux/ppc64le, (5 more)",
},
{
name: "riscv64 preferred only",
platforms: []string{"linux/riscv64*"},
max: 4,
expectedList: map[string][]string{
"linux/riscv64": {
"linux/riscv64*",
},
},
expectedOut: "linux/riscv64*",
},
{
name: "amd64 no preferred and emulated",
platforms: []string{"linux/amd64", "linux/amd64/v2", "linux/amd64/v3", "linux/386", "linux/arm64", "linux/riscv64", "linux/ppc64le", "linux/s390x", "linux/mips64le", "linux/mips64", "linux/arm/v7", "linux/arm/v6"},
max: 4,
expectedList: map[string][]string{
"linux/amd64": {
"linux/amd64",
"linux/amd64/v2",
"linux/amd64/v3",
},
"linux/arm": {
"linux/arm/v7",
"linux/arm/v6",
},
"linux/arm64": {
"linux/arm64",
},
"linux/ppc64le": {
"linux/ppc64le",
}},
expectedOut: "linux/amd64 (+3), linux/arm64, linux/arm (+2), linux/ppc64le, (5 more)",
},
{
name: "amd64 no preferred",
platforms: []string{"linux/amd64", "linux/386"},
max: 4,
expectedList: map[string][]string{
"linux/386": {
"linux/386",
},
"linux/amd64": {
"linux/amd64",
},
},
expectedOut: "linux/amd64, linux/386",
},
{
name: "arm64 no preferred",
platforms: []string{"linux/arm64", "linux/arm/v7", "linux/arm/v6"},
max: 4,
expectedList: map[string][]string{
"linux/arm": {
"linux/arm/v7",
"linux/arm/v6",
},
"linux/arm64": {
"linux/arm64",
},
},
expectedOut: "linux/arm64, linux/arm (+2)",
},
{
name: "all preferred",
platforms: []string{"darwin/arm64*", "linux/arm64*", "linux/arm/v5*", "linux/arm/v6*", "linux/arm/v7*", "windows/arm64*"},
max: 4,
expectedList: map[string][]string{
"darwin/arm64": {
"darwin/arm64*",
},
"linux/arm": {
"linux/arm/v5*",
"linux/arm/v6*",
"linux/arm/v7*",
},
"linux/arm64": {
"linux/arm64*",
},
"windows/arm64": {
"windows/arm64*",
},
},
expectedOut: "linux/arm64*, linux/arm* (+3), darwin/arm64*, windows/arm64*",
},
{
name: "no major preferred",
platforms: []string{"linux/amd64/v2*", "linux/arm/v6*", "linux/mips64le*", "linux/amd64", "linux/amd64/v3", "linux/386", "linux/arm64", "linux/riscv64", "linux/ppc64le", "linux/s390x", "linux/mips64", "linux/arm/v7"},
max: 4,
expectedList: map[string][]string{
"linux/amd64": {
"linux/amd64/v2*",
"linux/amd64",
"linux/amd64/v3",
},
"linux/arm": {
"linux/arm/v6*",
"linux/arm/v7",
},
"linux/arm64": {
"linux/arm64",
},
"linux/ppc64le": {
"linux/ppc64le",
},
},
expectedOut: "linux/amd64* (+3), linux/arm64, linux/arm* (+2), linux/ppc64le, (5 more)",
},
{
name: "no major with multiple variants",
platforms: []string{"linux/arm64", "linux/arm/v7", "linux/arm/v6", "linux/mips64le/softfloat", "linux/mips64le/hardfloat"},
max: 4,
expectedList: map[string][]string{
"linux/arm": {
"linux/arm/v7",
"linux/arm/v6",
},
"linux/arm64": {
"linux/arm64",
},
"linux/mips64le": {
"linux/mips64le/softfloat",
"linux/mips64le/hardfloat",
},
},
expectedOut: "linux/arm64, linux/arm (+2), linux/mips64le (+2)",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
tpfs := truncPlatforms(tt.platforms, tt.max)
assert.Equal(t, tt.expectedList, tpfs.List())
assert.Equal(t, tt.expectedOut, tpfs.String())
})
}
}

View File

@@ -22,12 +22,14 @@ import (
) )
type pruneOptions struct { type pruneOptions struct {
builder string builder string
all bool all bool
filter opts.FilterOpt filter opts.FilterOpt
keepStorage opts.MemBytes reservedSpace opts.MemBytes
force bool maxUsedSpace opts.MemBytes
verbose bool minFreeSpace opts.MemBytes
force bool
verbose bool
} }
const ( const (
@@ -106,7 +108,7 @@ func runPrune(ctx context.Context, dockerCli command.Cli, opts pruneOptions) err
return err return err
} }
popts := []client.PruneOption{ popts := []client.PruneOption{
client.WithKeepOpt(pi.KeepDuration, opts.keepStorage.Value()), client.WithKeepOpt(pi.KeepDuration, opts.reservedSpace.Value(), opts.maxUsedSpace.Value(), opts.minFreeSpace.Value()),
client.WithFilter(pi.Filter), client.WithFilter(pi.Filter),
} }
if opts.all { if opts.all {
@@ -148,10 +150,15 @@ func pruneCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
flags := cmd.Flags() flags := cmd.Flags()
flags.BoolVarP(&options.all, "all", "a", false, "Include internal/frontend images") flags.BoolVarP(&options.all, "all", "a", false, "Include internal/frontend images")
flags.Var(&options.filter, "filter", `Provide filter values (e.g., "until=24h")`) flags.Var(&options.filter, "filter", `Provide filter values (e.g., "until=24h")`)
flags.Var(&options.keepStorage, "keep-storage", "Amount of disk space to keep for cache") flags.Var(&options.reservedSpace, "reserved-space", "Amount of disk space always allowed to keep for cache")
flags.Var(&options.minFreeSpace, "min-free-space", "Target amount of free disk space after pruning")
flags.Var(&options.maxUsedSpace, "max-used-space", "Maximum amount of disk space allowed to keep for cache")
flags.BoolVar(&options.verbose, "verbose", false, "Provide a more verbose output") flags.BoolVar(&options.verbose, "verbose", false, "Provide a more verbose output")
flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation") flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation")
flags.Var(&options.reservedSpace, "keep-storage", "Amount of disk space to keep for cache")
flags.MarkDeprecated("keep-storage", "keep-storage flag has been changed to max-storage")
return cmd return cmd
} }

View File

@@ -1,6 +1,7 @@
package commands package commands
import ( import (
"fmt"
"os" "os"
debugcmd "github.com/docker/buildx/commands/debug" debugcmd "github.com/docker/buildx/commands/debug"
@@ -36,13 +37,22 @@ func NewRootCmd(name string, isPlugin bool, dockerCli command.Cli) *cobra.Comman
if opt.debug { if opt.debug {
debug.Enable() debug.Enable()
} }
cmd.SetContext(appcontext.Context()) cmd.SetContext(appcontext.Context())
if !isPlugin { if !isPlugin {
return nil return nil
} }
return plugin.PersistentPreRunE(cmd, args) return plugin.PersistentPreRunE(cmd, args)
}, },
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return cmd.Help()
}
_ = cmd.Help()
return cli.StatusError{
StatusCode: 1,
Status: fmt.Sprintf("ERROR: unknown command: %q", args[0]),
}
},
} }
if !isPlugin { if !isPlugin {
// match plugin behavior for standalone mode // match plugin behavior for standalone mode
@@ -95,7 +105,7 @@ func addCommands(cmd *cobra.Command, opts *rootOptions, dockerCli command.Cli) {
versionCmd(dockerCli), versionCmd(dockerCli),
pruneCmd(dockerCli, opts), pruneCmd(dockerCli, opts),
duCmd(dockerCli, opts), duCmd(dockerCli, opts),
imagetoolscmd.RootCmd(dockerCli, imagetoolscmd.RootOptions{Builder: &opts.builder}), imagetoolscmd.RootCmd(cmd, dockerCli, imagetoolscmd.RootOptions{Builder: &opts.builder}),
) )
if confutil.IsExperimental() { if confutil.IsExperimental() {
cmd.AddCommand(debugcmd.RootCmd(dockerCli, cmd.AddCommand(debugcmd.RootCmd(dockerCli,

View File

@@ -34,9 +34,9 @@ const defaultTargetName = "default"
// NOTE: When an error happens during the build and this function acquires the debuggable *build.ResultHandle, // NOTE: When an error happens during the build and this function acquires the debuggable *build.ResultHandle,
// this function returns it in addition to the error (i.e. it does "return nil, res, err"). The caller can // this function returns it in addition to the error (i.e. it does "return nil, res, err"). The caller can
// inspect the result and debug the cause of that error. // inspect the result and debug the cause of that error.
func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.BuildOptions, inStream io.Reader, progress progress.Writer, generateResult bool) (*client.SolveResponse, *build.ResultHandle, error) { func RunBuild(ctx context.Context, dockerCli command.Cli, in *controllerapi.BuildOptions, inStream io.Reader, progress progress.Writer, generateResult bool) (*client.SolveResponse, *build.ResultHandle, *build.Inputs, error) {
if in.NoCache && len(in.NoCacheFilter) > 0 { if in.NoCache && len(in.NoCacheFilter) > 0 {
return nil, nil, errors.Errorf("--no-cache and --no-cache-filter cannot currently be used together") return nil, nil, nil, errors.Errorf("--no-cache and --no-cache-filter cannot currently be used together")
} }
contexts := map[string]build.NamedContext{} contexts := map[string]build.NamedContext{}
@@ -70,7 +70,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
platforms, err := platformutil.Parse(in.Platforms) platforms, err := platformutil.Parse(in.Platforms)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
opts.Platforms = platforms opts.Platforms = platforms
@@ -79,7 +79,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
secrets, err := controllerapi.CreateSecrets(in.Secrets) secrets, err := controllerapi.CreateSecrets(in.Secrets)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
opts.Session = append(opts.Session, secrets) opts.Session = append(opts.Session, secrets)
@@ -89,13 +89,13 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
} }
ssh, err := controllerapi.CreateSSH(sshSpecs) ssh, err := controllerapi.CreateSSH(sshSpecs)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
opts.Session = append(opts.Session, ssh) opts.Session = append(opts.Session, ssh)
outputs, err := controllerapi.CreateExports(in.Exports) outputs, err := controllerapi.CreateExports(in.Exports)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
if in.ExportPush { if in.ExportPush {
var pushUsed bool var pushUsed bool
@@ -134,7 +134,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
annotations, err := buildflags.ParseAnnotations(in.Annotations) annotations, err := buildflags.ParseAnnotations(in.Annotations)
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "parse annotations") return nil, nil, nil, errors.Wrap(err, "parse annotations")
} }
for _, o := range outputs { for _, o := range outputs {
@@ -154,7 +154,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
allow, err := buildflags.ParseEntitlements(in.Allow) allow, err := buildflags.ParseEntitlements(in.Allow)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
opts.Allow = allow opts.Allow = allow
@@ -178,23 +178,28 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
builder.WithContextPathHash(contextPathHash), builder.WithContextPathHash(contextPathHash),
) )
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
if err = updateLastActivity(dockerCli, b.NodeGroup); err != nil { if err = updateLastActivity(dockerCli, b.NodeGroup); err != nil {
return nil, nil, errors.Wrapf(err, "failed to update builder last activity time") return nil, nil, nil, errors.Wrapf(err, "failed to update builder last activity time")
} }
nodes, err := b.LoadNodes(ctx) nodes, err := b.LoadNodes(ctx)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
resp, res, err := buildTargets(ctx, dockerCli, nodes, map[string]build.Options{defaultTargetName: opts}, progress, generateResult) var inputs *build.Inputs
buildOptions := map[string]build.Options{defaultTargetName: opts}
resp, res, err := buildTargets(ctx, dockerCli, nodes, buildOptions, progress, generateResult)
err = wrapBuildError(err, false) err = wrapBuildError(err, false)
if err != nil { if err != nil {
// NOTE: buildTargets can return *build.ResultHandle even on error. // NOTE: buildTargets can return *build.ResultHandle even on error.
return nil, res, err return nil, res, nil, err
} }
return resp, res, nil if i, ok := buildOptions[defaultTargetName]; ok {
inputs = &i.Inputs
}
return resp, res, inputs, nil
} }
// buildTargets runs the specified build and returns the result. // buildTargets runs the specified build and returns the result.
@@ -209,7 +214,7 @@ func buildTargets(ctx context.Context, dockerCli command.Cli, nodes []builder.No
if generateResult { if generateResult {
var mu sync.Mutex var mu sync.Mutex
var idx int var idx int
resp, err = build.BuildWithResultHandler(ctx, nodes, opts, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), progress, func(driverIndex int, gotRes *build.ResultHandle) { resp, err = build.BuildWithResultHandler(ctx, nodes, opts, dockerutil.NewClient(dockerCli), confutil.NewConfig(dockerCli), progress, func(driverIndex int, gotRes *build.ResultHandle) {
mu.Lock() mu.Lock()
defer mu.Unlock() defer mu.Unlock()
if res == nil || driverIndex < idx { if res == nil || driverIndex < idx {
@@ -217,7 +222,7 @@ func buildTargets(ctx context.Context, dockerCli command.Cli, nodes []builder.No
} }
}) })
} else { } else {
resp, err = build.Build(ctx, nodes, opts, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), progress) resp, err = build.Build(ctx, nodes, opts, dockerutil.NewClient(dockerCli), confutil.NewConfig(dockerCli), progress)
} }
if err != nil { if err != nil {
return nil, res, err return nil, res, err

View File

@@ -4,18 +4,19 @@ import (
"context" "context"
"io" "io"
"github.com/docker/buildx/build"
controllerapi "github.com/docker/buildx/controller/pb" controllerapi "github.com/docker/buildx/controller/pb"
"github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/progress"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
) )
type BuildxController interface { type BuildxController interface {
Build(ctx context.Context, options controllerapi.BuildOptions, in io.ReadCloser, progress progress.Writer) (ref string, resp *client.SolveResponse, err error) Build(ctx context.Context, options *controllerapi.BuildOptions, in io.ReadCloser, progress progress.Writer) (ref string, resp *client.SolveResponse, inputs *build.Inputs, err error)
// Invoke starts an IO session into the specified process. // Invoke starts an IO session into the specified process.
// If pid doesn't matche to any running processes, it starts a new process with the specified config. // If pid doesn't matche to any running processes, it starts a new process with the specified config.
// If there is no container running or InvokeConfig.Rollback is speicfied, the process will start in a newly created container. // If there is no container running or InvokeConfig.Rollback is speicfied, the process will start in a newly created container.
// NOTE: If needed, in the future, we can split this API into three APIs (NewContainer, NewProcess and Attach). // NOTE: If needed, in the future, we can split this API into three APIs (NewContainer, NewProcess and Attach).
Invoke(ctx context.Context, ref, pid string, options controllerapi.InvokeConfig, ioIn io.ReadCloser, ioOut io.WriteCloser, ioErr io.WriteCloser) error Invoke(ctx context.Context, ref, pid string, options *controllerapi.InvokeConfig, ioIn io.ReadCloser, ioOut io.WriteCloser, ioErr io.WriteCloser) error
Kill(ctx context.Context) error Kill(ctx context.Context) error
Close() error Close() error
List(ctx context.Context) (refs []string, _ error) List(ctx context.Context) (refs []string, _ error)

View File

@@ -1,7 +1,10 @@
package errdefs package errdefs
import ( import (
"io"
"github.com/containerd/typeurl/v2" "github.com/containerd/typeurl/v2"
"github.com/docker/buildx/util/desktop"
"github.com/moby/buildkit/util/grpcerrors" "github.com/moby/buildkit/util/grpcerrors"
) )
@@ -10,7 +13,7 @@ func init() {
} }
type BuildError struct { type BuildError struct {
Build *Build
error error
} }
@@ -19,16 +22,27 @@ func (e *BuildError) Unwrap() error {
} }
func (e *BuildError) ToProto() grpcerrors.TypedErrorProto { func (e *BuildError) ToProto() grpcerrors.TypedErrorProto {
return &e.Build return e.Build
} }
func WrapBuild(err error, ref string) error { func (e *BuildError) PrintBuildDetails(w io.Writer) error {
if e.Ref == "" {
return nil
}
ebr := &desktop.ErrorWithBuildRef{
Ref: e.Ref,
Err: e.error,
}
return ebr.Print(w)
}
func WrapBuild(err error, sessionID string, ref string) error {
if err == nil { if err == nil {
return nil return nil
} }
return &BuildError{Build: Build{Ref: ref}, error: err} return &BuildError{Build: &Build{SessionID: sessionID, Ref: ref}, error: err}
} }
func (b *Build) WrapError(err error) error { func (b *Build) WrapError(err error) error {
return &BuildError{error: err, Build: *b} return &BuildError{error: err, Build: b}
} }

View File

@@ -1,77 +1,157 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: errdefs.proto // versions:
// protoc-gen-go v1.34.1
// protoc v3.11.4
// source: github.com/docker/buildx/controller/errdefs/errdefs.proto
package errdefs package errdefs
import ( import (
fmt "fmt" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
proto "github.com/gogo/protobuf/proto" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
_ "github.com/moby/buildkit/solver/pb" reflect "reflect"
math "math" sync "sync"
) )
// Reference imports to suppress errors if they are not otherwise used. const (
var _ = proto.Marshal // Verify that this generated code is sufficiently up-to-date.
var _ = fmt.Errorf _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
var _ = math.Inf // Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
// This is a compile-time assertion to ensure that this generated file )
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type Build struct { type Build struct {
Ref string `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"` state protoimpl.MessageState
XXX_NoUnkeyedLiteral struct{} `json:"-"` sizeCache protoimpl.SizeCache
XXX_unrecognized []byte `json:"-"` unknownFields protoimpl.UnknownFields
XXX_sizecache int32 `json:"-"`
SessionID string `protobuf:"bytes,1,opt,name=SessionID,proto3" json:"SessionID,omitempty"`
Ref string `protobuf:"bytes,2,opt,name=Ref,proto3" json:"Ref,omitempty"`
} }
func (m *Build) Reset() { *m = Build{} } func (x *Build) Reset() {
func (m *Build) String() string { return proto.CompactTextString(m) } *x = Build{}
func (*Build) ProtoMessage() {} if protoimpl.UnsafeEnabled {
mi := &file_github_com_docker_buildx_controller_errdefs_errdefs_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Build) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Build) ProtoMessage() {}
func (x *Build) ProtoReflect() protoreflect.Message {
mi := &file_github_com_docker_buildx_controller_errdefs_errdefs_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Build.ProtoReflect.Descriptor instead.
func (*Build) Descriptor() ([]byte, []int) { func (*Build) Descriptor() ([]byte, []int) {
return fileDescriptor_689dc58a5060aff5, []int{0} return file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDescGZIP(), []int{0}
}
func (m *Build) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Build.Unmarshal(m, b)
}
func (m *Build) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Build.Marshal(b, m, deterministic)
}
func (m *Build) XXX_Merge(src proto.Message) {
xxx_messageInfo_Build.Merge(m, src)
}
func (m *Build) XXX_Size() int {
return xxx_messageInfo_Build.Size(m)
}
func (m *Build) XXX_DiscardUnknown() {
xxx_messageInfo_Build.DiscardUnknown(m)
} }
var xxx_messageInfo_Build proto.InternalMessageInfo func (x *Build) GetSessionID() string {
if x != nil {
func (m *Build) GetRef() string { return x.SessionID
if m != nil {
return m.Ref
} }
return "" return ""
} }
func init() { func (x *Build) GetRef() string {
proto.RegisterType((*Build)(nil), "errdefs.Build") if x != nil {
return x.Ref
}
return ""
} }
func init() { proto.RegisterFile("errdefs.proto", fileDescriptor_689dc58a5060aff5) } var File_github_com_docker_buildx_controller_errdefs_errdefs_proto protoreflect.FileDescriptor
var fileDescriptor_689dc58a5060aff5 = []byte{ var file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDesc = []byte{
// 111 bytes of a gzipped FileDescriptorProto 0x0a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x6f, 0x63,
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4d, 0x2d, 0x2a, 0x4a, 0x6b, 0x65, 0x72, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x78, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72,
0x49, 0x4d, 0x2b, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x87, 0x72, 0xa5, 0x74, 0xd2, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x65, 0x72, 0x72, 0x64, 0x65, 0x66, 0x73, 0x2f, 0x65, 0x72,
0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0x73, 0xf3, 0x93, 0x2a, 0xf5, 0x93, 0x72, 0x64, 0x65, 0x66, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x64, 0x6f, 0x63,
0x4a, 0x33, 0x73, 0x52, 0xb2, 0x33, 0x4b, 0xf4, 0x8b, 0xf3, 0x73, 0xca, 0x52, 0x8b, 0xf4, 0x0b, 0x6b, 0x65, 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x78, 0x2e, 0x65, 0x72, 0x72, 0x64, 0x65,
0x92, 0xf4, 0xf3, 0x0b, 0xa0, 0xda, 0x94, 0x24, 0xb9, 0x58, 0x9d, 0x40, 0xf2, 0x42, 0x02, 0x5c, 0x66, 0x73, 0x22, 0x37, 0x0a, 0x05, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x53,
0xcc, 0x41, 0xa9, 0x69, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x20, 0x66, 0x12, 0x1b, 0x58, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x85, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x56, 0x52, 0x41, 0x91, 0x69, 0x00, 0x00, 0x00, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x52, 0x65, 0x66,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x52, 0x65, 0x66, 0x42, 0x2d, 0x5a, 0x2b, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72,
0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x78, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
0x65, 0x72, 0x2f, 0x65, 0x72, 0x72, 0x64, 0x65, 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDescOnce sync.Once
file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDescData = file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDesc
)
func file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDescGZIP() []byte {
file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDescOnce.Do(func() {
file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDescData)
})
return file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDescData
}
var file_github_com_docker_buildx_controller_errdefs_errdefs_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_github_com_docker_buildx_controller_errdefs_errdefs_proto_goTypes = []interface{}{
(*Build)(nil), // 0: docker.buildx.errdefs.Build
}
var file_github_com_docker_buildx_controller_errdefs_errdefs_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_github_com_docker_buildx_controller_errdefs_errdefs_proto_init() }
func file_github_com_docker_buildx_controller_errdefs_errdefs_proto_init() {
if File_github_com_docker_buildx_controller_errdefs_errdefs_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_github_com_docker_buildx_controller_errdefs_errdefs_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Build); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_github_com_docker_buildx_controller_errdefs_errdefs_proto_goTypes,
DependencyIndexes: file_github_com_docker_buildx_controller_errdefs_errdefs_proto_depIdxs,
MessageInfos: file_github_com_docker_buildx_controller_errdefs_errdefs_proto_msgTypes,
}.Build()
File_github_com_docker_buildx_controller_errdefs_errdefs_proto = out.File
file_github_com_docker_buildx_controller_errdefs_errdefs_proto_rawDesc = nil
file_github_com_docker_buildx_controller_errdefs_errdefs_proto_goTypes = nil
file_github_com_docker_buildx_controller_errdefs_errdefs_proto_depIdxs = nil
} }

View File

@@ -1,9 +1,10 @@
syntax = "proto3"; syntax = "proto3";
package errdefs; package docker.buildx.errdefs;
import "github.com/moby/buildkit/solver/pb/ops.proto"; option go_package = "github.com/docker/buildx/controller/errdefs";
message Build { message Build {
string Ref = 1; string SessionID = 1;
} string Ref = 2;
}

View File

@@ -0,0 +1,241 @@
// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.
// protoc-gen-go-vtproto version: v0.6.1-0.20240319094008-0393e58bdf10
// source: github.com/docker/buildx/controller/errdefs/errdefs.proto
package errdefs
import (
fmt "fmt"
protohelpers "github.com/planetscale/vtprotobuf/protohelpers"
proto "google.golang.org/protobuf/proto"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
io "io"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
func (m *Build) CloneVT() *Build {
if m == nil {
return (*Build)(nil)
}
r := new(Build)
r.SessionID = m.SessionID
r.Ref = m.Ref
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields)
}
return r
}
func (m *Build) CloneMessageVT() proto.Message {
return m.CloneVT()
}
func (this *Build) EqualVT(that *Build) bool {
if this == that {
return true
} else if this == nil || that == nil {
return false
}
if this.SessionID != that.SessionID {
return false
}
if this.Ref != that.Ref {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
func (this *Build) EqualMessageVT(thatMsg proto.Message) bool {
that, ok := thatMsg.(*Build)
if !ok {
return false
}
return this.EqualVT(that)
}
func (m *Build) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Build) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *Build) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.Ref) > 0 {
i -= len(m.Ref)
copy(dAtA[i:], m.Ref)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Ref)))
i--
dAtA[i] = 0x12
}
if len(m.SessionID) > 0 {
i -= len(m.SessionID)
copy(dAtA[i:], m.SessionID)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SessionID)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *Build) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.SessionID)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.Ref)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
func (m *Build) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Build: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Build: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SessionID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.SessionID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Ref = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}

View File

@@ -1,3 +0,0 @@
package errdefs
//go:generate protoc -I=. -I=../../vendor/ --gogo_out=plugins=grpc:. errdefs.proto

View File

@@ -11,6 +11,7 @@ import (
controllererrors "github.com/docker/buildx/controller/errdefs" controllererrors "github.com/docker/buildx/controller/errdefs"
controllerapi "github.com/docker/buildx/controller/pb" controllerapi "github.com/docker/buildx/controller/pb"
"github.com/docker/buildx/controller/processes" "github.com/docker/buildx/controller/processes"
"github.com/docker/buildx/util/desktop"
"github.com/docker/buildx/util/ioset" "github.com/docker/buildx/util/ioset"
"github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/progress"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
@@ -21,7 +22,7 @@ import (
func NewLocalBuildxController(ctx context.Context, dockerCli command.Cli, logger progress.SubLogger) control.BuildxController { func NewLocalBuildxController(ctx context.Context, dockerCli command.Cli, logger progress.SubLogger) control.BuildxController {
return &localController{ return &localController{
dockerCli: dockerCli, dockerCli: dockerCli,
ref: "local", sessionID: "local",
processes: processes.NewManager(), processes: processes.NewManager(),
} }
} }
@@ -35,46 +36,51 @@ type buildConfig struct {
type localController struct { type localController struct {
dockerCli command.Cli dockerCli command.Cli
ref string sessionID string
buildConfig buildConfig buildConfig buildConfig
processes *processes.Manager processes *processes.Manager
buildOnGoing atomic.Bool buildOnGoing atomic.Bool
} }
func (b *localController) Build(ctx context.Context, options controllerapi.BuildOptions, in io.ReadCloser, progress progress.Writer) (string, *client.SolveResponse, error) { func (b *localController) Build(ctx context.Context, options *controllerapi.BuildOptions, in io.ReadCloser, progress progress.Writer) (string, *client.SolveResponse, *build.Inputs, error) {
if !b.buildOnGoing.CompareAndSwap(false, true) { if !b.buildOnGoing.CompareAndSwap(false, true) {
return "", nil, errors.New("build ongoing") return "", nil, nil, errors.New("build ongoing")
} }
defer b.buildOnGoing.Store(false) defer b.buildOnGoing.Store(false)
resp, res, buildErr := cbuild.RunBuild(ctx, b.dockerCli, options, in, progress, true) resp, res, dockerfileMappings, buildErr := cbuild.RunBuild(ctx, b.dockerCli, options, in, progress, true)
// NOTE: RunBuild can return *build.ResultHandle even on error. // NOTE: RunBuild can return *build.ResultHandle even on error.
if res != nil { if res != nil {
b.buildConfig = buildConfig{ b.buildConfig = buildConfig{
resultCtx: res, resultCtx: res,
buildOptions: &options, buildOptions: options,
} }
if buildErr != nil { if buildErr != nil {
buildErr = controllererrors.WrapBuild(buildErr, b.ref) var ref string
var ebr *desktop.ErrorWithBuildRef
if errors.As(buildErr, &ebr) {
ref = ebr.Ref
}
buildErr = controllererrors.WrapBuild(buildErr, b.sessionID, ref)
} }
} }
if buildErr != nil { if buildErr != nil {
return "", nil, buildErr return "", nil, nil, buildErr
} }
return b.ref, resp, nil return b.sessionID, resp, dockerfileMappings, nil
} }
func (b *localController) ListProcesses(ctx context.Context, ref string) (infos []*controllerapi.ProcessInfo, retErr error) { func (b *localController) ListProcesses(ctx context.Context, sessionID string) (infos []*controllerapi.ProcessInfo, retErr error) {
if ref != b.ref { if sessionID != b.sessionID {
return nil, errors.Errorf("unknown ref %q", ref) return nil, errors.Errorf("unknown session ID %q", sessionID)
} }
return b.processes.ListProcesses(), nil return b.processes.ListProcesses(), nil
} }
func (b *localController) DisconnectProcess(ctx context.Context, ref, pid string) error { func (b *localController) DisconnectProcess(ctx context.Context, sessionID, pid string) error {
if ref != b.ref { if sessionID != b.sessionID {
return errors.Errorf("unknown ref %q", ref) return errors.Errorf("unknown session ID %q", sessionID)
} }
return b.processes.DeleteProcess(pid) return b.processes.DeleteProcess(pid)
} }
@@ -83,9 +89,9 @@ func (b *localController) cancelRunningProcesses() {
b.processes.CancelRunningProcesses() b.processes.CancelRunningProcesses()
} }
func (b *localController) Invoke(ctx context.Context, ref string, pid string, cfg controllerapi.InvokeConfig, ioIn io.ReadCloser, ioOut io.WriteCloser, ioErr io.WriteCloser) error { func (b *localController) Invoke(ctx context.Context, sessionID string, pid string, cfg *controllerapi.InvokeConfig, ioIn io.ReadCloser, ioOut io.WriteCloser, ioErr io.WriteCloser) error {
if ref != b.ref { if sessionID != b.sessionID {
return errors.Errorf("unknown ref %q", ref) return errors.Errorf("unknown session ID %q", sessionID)
} }
proc, ok := b.processes.Get(pid) proc, ok := b.processes.Get(pid)
@@ -95,7 +101,7 @@ func (b *localController) Invoke(ctx context.Context, ref string, pid string, cf
return errors.New("no build result is registered") return errors.New("no build result is registered")
} }
var err error var err error
proc, err = b.processes.StartProcess(pid, b.buildConfig.resultCtx, &cfg) proc, err = b.processes.StartProcess(pid, b.buildConfig.resultCtx, cfg)
if err != nil { if err != nil {
return err return err
} }
@@ -130,7 +136,7 @@ func (b *localController) Close() error {
} }
func (b *localController) List(ctx context.Context) (res []string, _ error) { func (b *localController) List(ctx context.Context) (res []string, _ error) {
return []string{b.ref}, nil return []string{b.sessionID}, nil
} }
func (b *localController) Disconnect(ctx context.Context, key string) error { func (b *localController) Disconnect(ctx context.Context, key string) error {
@@ -138,9 +144,9 @@ func (b *localController) Disconnect(ctx context.Context, key string) error {
return nil return nil
} }
func (b *localController) Inspect(ctx context.Context, ref string) (*controllerapi.InspectResponse, error) { func (b *localController) Inspect(ctx context.Context, sessionID string) (*controllerapi.InspectResponse, error) {
if ref != b.ref { if sessionID != b.sessionID {
return nil, errors.Errorf("unknown ref %q", ref) return nil, errors.Errorf("unknown session ID %q", sessionID)
} }
return &controllerapi.InspectResponse{Options: b.buildConfig.buildOptions}, nil return &controllerapi.InspectResponse{Options: b.buildConfig.buildOptions}, nil
} }

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ package buildx.controller.v1;
import "github.com/moby/buildkit/api/services/control/control.proto"; import "github.com/moby/buildkit/api/services/control/control.proto";
import "github.com/moby/buildkit/sourcepolicy/pb/policy.proto"; import "github.com/moby/buildkit/sourcepolicy/pb/policy.proto";
option go_package = "pb"; option go_package = "github.com/docker/buildx/controller/pb";
service Controller { service Controller {
rpc Build(BuildRequest) returns (BuildResponse); rpc Build(BuildRequest) returns (BuildResponse);
@@ -21,7 +21,7 @@ service Controller {
} }
message ListProcessesRequest { message ListProcessesRequest {
string Ref = 1; string SessionID = 1;
} }
message ListProcessesResponse { message ListProcessesResponse {
@@ -34,7 +34,7 @@ message ProcessInfo {
} }
message DisconnectProcessRequest { message DisconnectProcessRequest {
string Ref = 1; string SessionID = 1;
string ProcessID = 2; string ProcessID = 2;
} }
@@ -42,7 +42,7 @@ message DisconnectProcessResponse {
} }
message BuildRequest { message BuildRequest {
string Ref = 1; string SessionID = 1;
BuildOptions Options = 2; BuildOptions Options = 2;
} }
@@ -118,7 +118,7 @@ message CallFunc {
} }
message InspectRequest { message InspectRequest {
string Ref = 1; string SessionID = 1;
} }
message InspectResponse { message InspectResponse {
@@ -140,13 +140,13 @@ message BuildResponse {
} }
message DisconnectRequest { message DisconnectRequest {
string Ref = 1; string SessionID = 1;
} }
message DisconnectResponse {} message DisconnectResponse {}
message ListRequest { message ListRequest {
string Ref = 1; string SessionID = 1;
} }
message ListResponse { message ListResponse {
@@ -161,7 +161,7 @@ message InputMessage {
} }
message InputInitMessage { message InputInitMessage {
string Ref = 1; string SessionID = 1;
} }
message DataMessage { message DataMessage {
@@ -186,7 +186,7 @@ message Message {
} }
message InitMessage { message InitMessage {
string Ref = 1; string SessionID = 1;
// If ProcessID already exists in the server, it tries to connect to it // If ProcessID already exists in the server, it tries to connect to it
// instead of invoking the new one. In this case, InvokeConfig will be ignored. // instead of invoking the new one. In this case, InvokeConfig will be ignored.
@@ -227,7 +227,7 @@ message SignalMessage {
} }
message StatusRequest { message StatusRequest {
string Ref = 1; string SessionID = 1;
} }
message StatusResponse { message StatusResponse {

View File

@@ -0,0 +1,452 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v3.11.4
// source: github.com/docker/buildx/controller/pb/controller.proto
package pb
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Controller_Build_FullMethodName = "/buildx.controller.v1.Controller/Build"
Controller_Inspect_FullMethodName = "/buildx.controller.v1.Controller/Inspect"
Controller_Status_FullMethodName = "/buildx.controller.v1.Controller/Status"
Controller_Input_FullMethodName = "/buildx.controller.v1.Controller/Input"
Controller_Invoke_FullMethodName = "/buildx.controller.v1.Controller/Invoke"
Controller_List_FullMethodName = "/buildx.controller.v1.Controller/List"
Controller_Disconnect_FullMethodName = "/buildx.controller.v1.Controller/Disconnect"
Controller_Info_FullMethodName = "/buildx.controller.v1.Controller/Info"
Controller_ListProcesses_FullMethodName = "/buildx.controller.v1.Controller/ListProcesses"
Controller_DisconnectProcess_FullMethodName = "/buildx.controller.v1.Controller/DisconnectProcess"
)
// ControllerClient is the client API for Controller service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ControllerClient interface {
Build(ctx context.Context, in *BuildRequest, opts ...grpc.CallOption) (*BuildResponse, error)
Inspect(ctx context.Context, in *InspectRequest, opts ...grpc.CallOption) (*InspectResponse, error)
Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StatusResponse], error)
Input(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[InputMessage, InputResponse], error)
Invoke(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[Message, Message], error)
List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error)
Disconnect(ctx context.Context, in *DisconnectRequest, opts ...grpc.CallOption) (*DisconnectResponse, error)
Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error)
ListProcesses(ctx context.Context, in *ListProcessesRequest, opts ...grpc.CallOption) (*ListProcessesResponse, error)
DisconnectProcess(ctx context.Context, in *DisconnectProcessRequest, opts ...grpc.CallOption) (*DisconnectProcessResponse, error)
}
type controllerClient struct {
cc grpc.ClientConnInterface
}
func NewControllerClient(cc grpc.ClientConnInterface) ControllerClient {
return &controllerClient{cc}
}
func (c *controllerClient) Build(ctx context.Context, in *BuildRequest, opts ...grpc.CallOption) (*BuildResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(BuildResponse)
err := c.cc.Invoke(ctx, Controller_Build_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *controllerClient) Inspect(ctx context.Context, in *InspectRequest, opts ...grpc.CallOption) (*InspectResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(InspectResponse)
err := c.cc.Invoke(ctx, Controller_Inspect_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *controllerClient) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StatusResponse], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &Controller_ServiceDesc.Streams[0], Controller_Status_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[StatusRequest, StatusResponse]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Controller_StatusClient = grpc.ServerStreamingClient[StatusResponse]
func (c *controllerClient) Input(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[InputMessage, InputResponse], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &Controller_ServiceDesc.Streams[1], Controller_Input_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[InputMessage, InputResponse]{ClientStream: stream}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Controller_InputClient = grpc.ClientStreamingClient[InputMessage, InputResponse]
func (c *controllerClient) Invoke(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[Message, Message], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &Controller_ServiceDesc.Streams[2], Controller_Invoke_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[Message, Message]{ClientStream: stream}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Controller_InvokeClient = grpc.BidiStreamingClient[Message, Message]
func (c *controllerClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListResponse)
err := c.cc.Invoke(ctx, Controller_List_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *controllerClient) Disconnect(ctx context.Context, in *DisconnectRequest, opts ...grpc.CallOption) (*DisconnectResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(DisconnectResponse)
err := c.cc.Invoke(ctx, Controller_Disconnect_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *controllerClient) Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(InfoResponse)
err := c.cc.Invoke(ctx, Controller_Info_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *controllerClient) ListProcesses(ctx context.Context, in *ListProcessesRequest, opts ...grpc.CallOption) (*ListProcessesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListProcessesResponse)
err := c.cc.Invoke(ctx, Controller_ListProcesses_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *controllerClient) DisconnectProcess(ctx context.Context, in *DisconnectProcessRequest, opts ...grpc.CallOption) (*DisconnectProcessResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(DisconnectProcessResponse)
err := c.cc.Invoke(ctx, Controller_DisconnectProcess_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// ControllerServer is the server API for Controller service.
// All implementations should embed UnimplementedControllerServer
// for forward compatibility.
type ControllerServer interface {
Build(context.Context, *BuildRequest) (*BuildResponse, error)
Inspect(context.Context, *InspectRequest) (*InspectResponse, error)
Status(*StatusRequest, grpc.ServerStreamingServer[StatusResponse]) error
Input(grpc.ClientStreamingServer[InputMessage, InputResponse]) error
Invoke(grpc.BidiStreamingServer[Message, Message]) error
List(context.Context, *ListRequest) (*ListResponse, error)
Disconnect(context.Context, *DisconnectRequest) (*DisconnectResponse, error)
Info(context.Context, *InfoRequest) (*InfoResponse, error)
ListProcesses(context.Context, *ListProcessesRequest) (*ListProcessesResponse, error)
DisconnectProcess(context.Context, *DisconnectProcessRequest) (*DisconnectProcessResponse, error)
}
// UnimplementedControllerServer should be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedControllerServer struct{}
func (UnimplementedControllerServer) Build(context.Context, *BuildRequest) (*BuildResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Build not implemented")
}
func (UnimplementedControllerServer) Inspect(context.Context, *InspectRequest) (*InspectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Inspect not implemented")
}
func (UnimplementedControllerServer) Status(*StatusRequest, grpc.ServerStreamingServer[StatusResponse]) error {
return status.Errorf(codes.Unimplemented, "method Status not implemented")
}
func (UnimplementedControllerServer) Input(grpc.ClientStreamingServer[InputMessage, InputResponse]) error {
return status.Errorf(codes.Unimplemented, "method Input not implemented")
}
func (UnimplementedControllerServer) Invoke(grpc.BidiStreamingServer[Message, Message]) error {
return status.Errorf(codes.Unimplemented, "method Invoke not implemented")
}
func (UnimplementedControllerServer) List(context.Context, *ListRequest) (*ListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method List not implemented")
}
func (UnimplementedControllerServer) Disconnect(context.Context, *DisconnectRequest) (*DisconnectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Disconnect not implemented")
}
func (UnimplementedControllerServer) Info(context.Context, *InfoRequest) (*InfoResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Info not implemented")
}
func (UnimplementedControllerServer) ListProcesses(context.Context, *ListProcessesRequest) (*ListProcessesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListProcesses not implemented")
}
func (UnimplementedControllerServer) DisconnectProcess(context.Context, *DisconnectProcessRequest) (*DisconnectProcessResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DisconnectProcess not implemented")
}
func (UnimplementedControllerServer) testEmbeddedByValue() {}
// UnsafeControllerServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ControllerServer will
// result in compilation errors.
type UnsafeControllerServer interface {
mustEmbedUnimplementedControllerServer()
}
func RegisterControllerServer(s grpc.ServiceRegistrar, srv ControllerServer) {
// If the following call pancis, it indicates UnimplementedControllerServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Controller_ServiceDesc, srv)
}
func _Controller_Build_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BuildRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControllerServer).Build(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Controller_Build_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControllerServer).Build(ctx, req.(*BuildRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Controller_Inspect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(InspectRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControllerServer).Inspect(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Controller_Inspect_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControllerServer).Inspect(ctx, req.(*InspectRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Controller_Status_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(StatusRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ControllerServer).Status(m, &grpc.GenericServerStream[StatusRequest, StatusResponse]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Controller_StatusServer = grpc.ServerStreamingServer[StatusResponse]
func _Controller_Input_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(ControllerServer).Input(&grpc.GenericServerStream[InputMessage, InputResponse]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Controller_InputServer = grpc.ClientStreamingServer[InputMessage, InputResponse]
func _Controller_Invoke_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(ControllerServer).Invoke(&grpc.GenericServerStream[Message, Message]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type Controller_InvokeServer = grpc.BidiStreamingServer[Message, Message]
func _Controller_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControllerServer).List(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Controller_List_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControllerServer).List(ctx, req.(*ListRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Controller_Disconnect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DisconnectRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControllerServer).Disconnect(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Controller_Disconnect_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControllerServer).Disconnect(ctx, req.(*DisconnectRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Controller_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(InfoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControllerServer).Info(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Controller_Info_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControllerServer).Info(ctx, req.(*InfoRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Controller_ListProcesses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListProcessesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControllerServer).ListProcesses(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Controller_ListProcesses_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControllerServer).ListProcesses(ctx, req.(*ListProcessesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Controller_DisconnectProcess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DisconnectProcessRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControllerServer).DisconnectProcess(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Controller_DisconnectProcess_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControllerServer).DisconnectProcess(ctx, req.(*DisconnectProcessRequest))
}
return interceptor(ctx, in, info, handler)
}
// Controller_ServiceDesc is the grpc.ServiceDesc for Controller service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Controller_ServiceDesc = grpc.ServiceDesc{
ServiceName: "buildx.controller.v1.Controller",
HandlerType: (*ControllerServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Build",
Handler: _Controller_Build_Handler,
},
{
MethodName: "Inspect",
Handler: _Controller_Inspect_Handler,
},
{
MethodName: "List",
Handler: _Controller_List_Handler,
},
{
MethodName: "Disconnect",
Handler: _Controller_Disconnect_Handler,
},
{
MethodName: "Info",
Handler: _Controller_Info_Handler,
},
{
MethodName: "ListProcesses",
Handler: _Controller_ListProcesses_Handler,
},
{
MethodName: "DisconnectProcess",
Handler: _Controller_DisconnectProcess_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "Status",
Handler: _Controller_Status_Handler,
ServerStreams: true,
},
{
StreamName: "Input",
Handler: _Controller_Input_Handler,
ClientStreams: true,
},
{
StreamName: "Invoke",
Handler: _Controller_Invoke_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "github.com/docker/buildx/controller/pb/controller.proto",
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +0,0 @@
package pb
//go:generate protoc -I=. -I=../../vendor/ --gogo_out=plugins=grpc:. controller.proto

View File

@@ -3,10 +3,10 @@ package pb
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
) )
func TestResolvePaths(t *testing.T) { func TestResolvePaths(t *testing.T) {
@@ -16,54 +16,58 @@ func TestResolvePaths(t *testing.T) {
require.NoError(t, os.Chdir(tmpwd)) require.NoError(t, os.Chdir(tmpwd))
tests := []struct { tests := []struct {
name string name string
options BuildOptions options *BuildOptions
want BuildOptions want *BuildOptions
}{ }{
{ {
name: "contextpath", name: "contextpath",
options: BuildOptions{ContextPath: "test"}, options: &BuildOptions{ContextPath: "test"},
want: BuildOptions{ContextPath: filepath.Join(tmpwd, "test")}, want: &BuildOptions{ContextPath: filepath.Join(tmpwd, "test")},
}, },
{ {
name: "contextpath-cwd", name: "contextpath-cwd",
options: BuildOptions{ContextPath: "."}, options: &BuildOptions{ContextPath: "."},
want: BuildOptions{ContextPath: tmpwd}, want: &BuildOptions{ContextPath: tmpwd},
}, },
{ {
name: "contextpath-dash", name: "contextpath-dash",
options: BuildOptions{ContextPath: "-"}, options: &BuildOptions{ContextPath: "-"},
want: BuildOptions{ContextPath: "-"}, want: &BuildOptions{ContextPath: "-"},
}, },
{ {
name: "contextpath-ssh", name: "contextpath-ssh",
options: BuildOptions{ContextPath: "git@github.com:docker/buildx.git"}, options: &BuildOptions{ContextPath: "git@github.com:docker/buildx.git"},
want: BuildOptions{ContextPath: "git@github.com:docker/buildx.git"}, want: &BuildOptions{ContextPath: "git@github.com:docker/buildx.git"},
}, },
{ {
name: "dockerfilename", name: "dockerfilename",
options: BuildOptions{DockerfileName: "test", ContextPath: "."}, options: &BuildOptions{DockerfileName: "test", ContextPath: "."},
want: BuildOptions{DockerfileName: filepath.Join(tmpwd, "test"), ContextPath: tmpwd}, want: &BuildOptions{DockerfileName: filepath.Join(tmpwd, "test"), ContextPath: tmpwd},
}, },
{ {
name: "dockerfilename-dash", name: "dockerfilename-dash",
options: BuildOptions{DockerfileName: "-", ContextPath: "."}, options: &BuildOptions{DockerfileName: "-", ContextPath: "."},
want: BuildOptions{DockerfileName: "-", ContextPath: tmpwd}, want: &BuildOptions{DockerfileName: "-", ContextPath: tmpwd},
}, },
{ {
name: "dockerfilename-remote", name: "dockerfilename-remote",
options: BuildOptions{DockerfileName: "test", ContextPath: "git@github.com:docker/buildx.git"}, options: &BuildOptions{DockerfileName: "test", ContextPath: "git@github.com:docker/buildx.git"},
want: BuildOptions{DockerfileName: "test", ContextPath: "git@github.com:docker/buildx.git"}, want: &BuildOptions{DockerfileName: "test", ContextPath: "git@github.com:docker/buildx.git"},
}, },
{ {
name: "contexts", name: "contexts",
options: BuildOptions{NamedContexts: map[string]string{"a": "test1", "b": "test2", options: &BuildOptions{NamedContexts: map[string]string{
"alpine": "docker-image://alpine@sha256:0123456789", "project": "https://github.com/myuser/project.git"}}, "a": "test1", "b": "test2",
want: BuildOptions{NamedContexts: map[string]string{"a": filepath.Join(tmpwd, "test1"), "b": filepath.Join(tmpwd, "test2"), "alpine": "docker-image://alpine@sha256:0123456789", "project": "https://github.com/myuser/project.git",
"alpine": "docker-image://alpine@sha256:0123456789", "project": "https://github.com/myuser/project.git"}}, }},
want: &BuildOptions{NamedContexts: map[string]string{
"a": filepath.Join(tmpwd, "test1"), "b": filepath.Join(tmpwd, "test2"),
"alpine": "docker-image://alpine@sha256:0123456789", "project": "https://github.com/myuser/project.git",
}},
}, },
{ {
name: "cache-from", name: "cache-from",
options: BuildOptions{ options: &BuildOptions{
CacheFrom: []*CacheOptionsEntry{ CacheFrom: []*CacheOptionsEntry{
{ {
Type: "local", Type: "local",
@@ -75,7 +79,7 @@ func TestResolvePaths(t *testing.T) {
}, },
}, },
}, },
want: BuildOptions{ want: &BuildOptions{
CacheFrom: []*CacheOptionsEntry{ CacheFrom: []*CacheOptionsEntry{
{ {
Type: "local", Type: "local",
@@ -90,7 +94,7 @@ func TestResolvePaths(t *testing.T) {
}, },
{ {
name: "cache-to", name: "cache-to",
options: BuildOptions{ options: &BuildOptions{
CacheTo: []*CacheOptionsEntry{ CacheTo: []*CacheOptionsEntry{
{ {
Type: "local", Type: "local",
@@ -102,7 +106,7 @@ func TestResolvePaths(t *testing.T) {
}, },
}, },
}, },
want: BuildOptions{ want: &BuildOptions{
CacheTo: []*CacheOptionsEntry{ CacheTo: []*CacheOptionsEntry{
{ {
Type: "local", Type: "local",
@@ -117,7 +121,7 @@ func TestResolvePaths(t *testing.T) {
}, },
{ {
name: "exports", name: "exports",
options: BuildOptions{ options: &BuildOptions{
Exports: []*ExportEntry{ Exports: []*ExportEntry{
{ {
Type: "local", Type: "local",
@@ -145,7 +149,7 @@ func TestResolvePaths(t *testing.T) {
}, },
}, },
}, },
want: BuildOptions{ want: &BuildOptions{
Exports: []*ExportEntry{ Exports: []*ExportEntry{
{ {
Type: "local", Type: "local",
@@ -176,7 +180,7 @@ func TestResolvePaths(t *testing.T) {
}, },
{ {
name: "secrets", name: "secrets",
options: BuildOptions{ options: &BuildOptions{
Secrets: []*Secret{ Secrets: []*Secret{
{ {
FilePath: "test1", FilePath: "test1",
@@ -191,7 +195,7 @@ func TestResolvePaths(t *testing.T) {
}, },
}, },
}, },
want: BuildOptions{ want: &BuildOptions{
Secrets: []*Secret{ Secrets: []*Secret{
{ {
FilePath: filepath.Join(tmpwd, "test1"), FilePath: filepath.Join(tmpwd, "test1"),
@@ -209,7 +213,7 @@ func TestResolvePaths(t *testing.T) {
}, },
{ {
name: "ssh", name: "ssh",
options: BuildOptions{ options: &BuildOptions{
SSH: []*SSH{ SSH: []*SSH{
{ {
ID: "default", ID: "default",
@@ -221,7 +225,7 @@ func TestResolvePaths(t *testing.T) {
}, },
}, },
}, },
want: BuildOptions{ want: &BuildOptions{
SSH: []*SSH{ SSH: []*SSH{
{ {
ID: "default", ID: "default",
@@ -238,10 +242,10 @@ func TestResolvePaths(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
tt := tt tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := ResolveOptionPaths(&tt.options) got, err := ResolveOptionPaths(tt.options)
require.NoError(t, err) require.NoError(t, err)
if !reflect.DeepEqual(tt.want, *got) { if !proto.Equal(tt.want, got) {
t.Fatalf("expected %#v, got %#v", tt.want, *got) t.Fatalf("expected %#v, got %#v", tt.want, got)
} }
}) })
} }

View File

@@ -1,10 +1,13 @@
package pb package pb
import ( import (
"time"
"github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/progress"
control "github.com/moby/buildkit/api/services/control" control "github.com/moby/buildkit/api/services/control"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"google.golang.org/protobuf/types/known/timestamppb"
) )
type writer struct { type writer struct {
@@ -33,11 +36,11 @@ func ToControlStatus(s *client.SolveStatus) *StatusResponse {
resp := StatusResponse{} resp := StatusResponse{}
for _, v := range s.Vertexes { for _, v := range s.Vertexes {
resp.Vertexes = append(resp.Vertexes, &control.Vertex{ resp.Vertexes = append(resp.Vertexes, &control.Vertex{
Digest: v.Digest, Digest: string(v.Digest),
Inputs: v.Inputs, Inputs: digestSliceToPB(v.Inputs),
Name: v.Name, Name: v.Name,
Started: v.Started, Started: timestampToPB(v.Started),
Completed: v.Completed, Completed: timestampToPB(v.Completed),
Error: v.Error, Error: v.Error,
Cached: v.Cached, Cached: v.Cached,
ProgressGroup: v.ProgressGroup, ProgressGroup: v.ProgressGroup,
@@ -46,26 +49,26 @@ func ToControlStatus(s *client.SolveStatus) *StatusResponse {
for _, v := range s.Statuses { for _, v := range s.Statuses {
resp.Statuses = append(resp.Statuses, &control.VertexStatus{ resp.Statuses = append(resp.Statuses, &control.VertexStatus{
ID: v.ID, ID: v.ID,
Vertex: v.Vertex, Vertex: string(v.Vertex),
Name: v.Name, Name: v.Name,
Total: v.Total, Total: v.Total,
Current: v.Current, Current: v.Current,
Timestamp: v.Timestamp, Timestamp: timestamppb.New(v.Timestamp),
Started: v.Started, Started: timestampToPB(v.Started),
Completed: v.Completed, Completed: timestampToPB(v.Completed),
}) })
} }
for _, v := range s.Logs { for _, v := range s.Logs {
resp.Logs = append(resp.Logs, &control.VertexLog{ resp.Logs = append(resp.Logs, &control.VertexLog{
Vertex: v.Vertex, Vertex: string(v.Vertex),
Stream: int64(v.Stream), Stream: int64(v.Stream),
Msg: v.Data, Msg: v.Data,
Timestamp: v.Timestamp, Timestamp: timestamppb.New(v.Timestamp),
}) })
} }
for _, v := range s.Warnings { for _, v := range s.Warnings {
resp.Warnings = append(resp.Warnings, &control.VertexWarning{ resp.Warnings = append(resp.Warnings, &control.VertexWarning{
Vertex: v.Vertex, Vertex: string(v.Vertex),
Level: int64(v.Level), Level: int64(v.Level),
Short: v.Short, Short: v.Short,
Detail: v.Detail, Detail: v.Detail,
@@ -81,11 +84,11 @@ func FromControlStatus(resp *StatusResponse) *client.SolveStatus {
s := client.SolveStatus{} s := client.SolveStatus{}
for _, v := range resp.Vertexes { for _, v := range resp.Vertexes {
s.Vertexes = append(s.Vertexes, &client.Vertex{ s.Vertexes = append(s.Vertexes, &client.Vertex{
Digest: v.Digest, Digest: digest.Digest(v.Digest),
Inputs: v.Inputs, Inputs: digestSliceFromPB(v.Inputs),
Name: v.Name, Name: v.Name,
Started: v.Started, Started: timestampFromPB(v.Started),
Completed: v.Completed, Completed: timestampFromPB(v.Completed),
Error: v.Error, Error: v.Error,
Cached: v.Cached, Cached: v.Cached,
ProgressGroup: v.ProgressGroup, ProgressGroup: v.ProgressGroup,
@@ -94,26 +97,26 @@ func FromControlStatus(resp *StatusResponse) *client.SolveStatus {
for _, v := range resp.Statuses { for _, v := range resp.Statuses {
s.Statuses = append(s.Statuses, &client.VertexStatus{ s.Statuses = append(s.Statuses, &client.VertexStatus{
ID: v.ID, ID: v.ID,
Vertex: v.Vertex, Vertex: digest.Digest(v.Vertex),
Name: v.Name, Name: v.Name,
Total: v.Total, Total: v.Total,
Current: v.Current, Current: v.Current,
Timestamp: v.Timestamp, Timestamp: v.Timestamp.AsTime(),
Started: v.Started, Started: timestampFromPB(v.Started),
Completed: v.Completed, Completed: timestampFromPB(v.Completed),
}) })
} }
for _, v := range resp.Logs { for _, v := range resp.Logs {
s.Logs = append(s.Logs, &client.VertexLog{ s.Logs = append(s.Logs, &client.VertexLog{
Vertex: v.Vertex, Vertex: digest.Digest(v.Vertex),
Stream: int(v.Stream), Stream: int(v.Stream),
Data: v.Msg, Data: v.Msg,
Timestamp: v.Timestamp, Timestamp: v.Timestamp.AsTime(),
}) })
} }
for _, v := range resp.Warnings { for _, v := range resp.Warnings {
s.Warnings = append(s.Warnings, &client.VertexWarning{ s.Warnings = append(s.Warnings, &client.VertexWarning{
Vertex: v.Vertex, Vertex: digest.Digest(v.Vertex),
Level: int(v.Level), Level: int(v.Level),
Short: v.Short, Short: v.Short,
Detail: v.Detail, Detail: v.Detail,
@@ -124,3 +127,38 @@ func FromControlStatus(resp *StatusResponse) *client.SolveStatus {
} }
return &s return &s
} }
func timestampFromPB(ts *timestamppb.Timestamp) *time.Time {
if ts == nil {
return nil
}
t := ts.AsTime()
if t.IsZero() {
return nil
}
return &t
}
func timestampToPB(ts *time.Time) *timestamppb.Timestamp {
if ts == nil {
return nil
}
return timestamppb.New(*ts)
}
func digestSliceFromPB(elems []string) []digest.Digest {
clone := make([]digest.Digest, len(elems))
for i, e := range elems {
clone[i] = digest.Digest(e)
}
return clone
}
func digestSliceToPB(elems []digest.Digest) []string {
clone := make([]string, len(elems))
for i, e := range elems {
clone[i] = string(e)
}
return clone
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/containerd/containerd/defaults" "github.com/containerd/containerd/defaults"
"github.com/containerd/containerd/pkg/dialer" "github.com/containerd/containerd/pkg/dialer"
"github.com/docker/buildx/build"
"github.com/docker/buildx/controller/pb" "github.com/docker/buildx/controller/pb"
"github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/progress"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
@@ -27,6 +28,7 @@ func NewClient(ctx context.Context, addr string) (*Client, error) {
Backoff: backoffConfig, Backoff: backoffConfig,
} }
gopts := []grpc.DialOption{ gopts := []grpc.DialOption{
//nolint:staticcheck // ignore SA1019: WithBlock is deprecated and does not work with NewClient.
grpc.WithBlock(), grpc.WithBlock(),
grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithConnectParams(connParams), grpc.WithConnectParams(connParams),
@@ -36,6 +38,7 @@ func NewClient(ctx context.Context, addr string) (*Client, error) {
grpc.WithUnaryInterceptor(grpcerrors.UnaryClientInterceptor), grpc.WithUnaryInterceptor(grpcerrors.UnaryClientInterceptor),
grpc.WithStreamInterceptor(grpcerrors.StreamClientInterceptor), grpc.WithStreamInterceptor(grpcerrors.StreamClientInterceptor),
} }
//nolint:staticcheck // ignore SA1019: Recommended NewClient has different behavior from DialContext.
conn, err := grpc.DialContext(ctx, dialer.DialAddress(addr), gopts...) conn, err := grpc.DialContext(ctx, dialer.DialAddress(addr), gopts...)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -72,36 +75,36 @@ func (c *Client) List(ctx context.Context) (keys []string, retErr error) {
return res.Keys, nil return res.Keys, nil
} }
func (c *Client) Disconnect(ctx context.Context, key string) error { func (c *Client) Disconnect(ctx context.Context, sessionID string) error {
if key == "" { if sessionID == "" {
return nil return nil
} }
_, err := c.client().Disconnect(ctx, &pb.DisconnectRequest{Ref: key}) _, err := c.client().Disconnect(ctx, &pb.DisconnectRequest{SessionID: sessionID})
return err return err
} }
func (c *Client) ListProcesses(ctx context.Context, ref string) (infos []*pb.ProcessInfo, retErr error) { func (c *Client) ListProcesses(ctx context.Context, sessionID string) (infos []*pb.ProcessInfo, retErr error) {
res, err := c.client().ListProcesses(ctx, &pb.ListProcessesRequest{Ref: ref}) res, err := c.client().ListProcesses(ctx, &pb.ListProcessesRequest{SessionID: sessionID})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return res.Infos, nil return res.Infos, nil
} }
func (c *Client) DisconnectProcess(ctx context.Context, ref, pid string) error { func (c *Client) DisconnectProcess(ctx context.Context, sessionID, pid string) error {
_, err := c.client().DisconnectProcess(ctx, &pb.DisconnectProcessRequest{Ref: ref, ProcessID: pid}) _, err := c.client().DisconnectProcess(ctx, &pb.DisconnectProcessRequest{SessionID: sessionID, ProcessID: pid})
return err return err
} }
func (c *Client) Invoke(ctx context.Context, ref string, pid string, invokeConfig pb.InvokeConfig, in io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser) error { func (c *Client) Invoke(ctx context.Context, sessionID string, pid string, invokeConfig *pb.InvokeConfig, in io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser) error {
if ref == "" || pid == "" { if sessionID == "" || pid == "" {
return errors.New("build reference must be specified") return errors.New("build session ID must be specified")
} }
stream, err := c.client().Invoke(ctx) stream, err := c.client().Invoke(ctx)
if err != nil { if err != nil {
return err return err
} }
return attachIO(ctx, stream, &pb.InitMessage{Ref: ref, ProcessID: pid, InvokeConfig: &invokeConfig}, ioAttachConfig{ return attachIO(ctx, stream, &pb.InitMessage{SessionID: sessionID, ProcessID: pid, InvokeConfig: invokeConfig}, ioAttachConfig{
stdin: in, stdin: in,
stdout: stdout, stdout: stdout,
stderr: stderr, stderr: stderr,
@@ -109,11 +112,11 @@ func (c *Client) Invoke(ctx context.Context, ref string, pid string, invokeConfi
}) })
} }
func (c *Client) Inspect(ctx context.Context, ref string) (*pb.InspectResponse, error) { func (c *Client) Inspect(ctx context.Context, sessionID string) (*pb.InspectResponse, error) {
return c.client().Inspect(ctx, &pb.InspectRequest{Ref: ref}) return c.client().Inspect(ctx, &pb.InspectRequest{SessionID: sessionID})
} }
func (c *Client) Build(ctx context.Context, options pb.BuildOptions, in io.ReadCloser, progress progress.Writer) (string, *client.SolveResponse, error) { func (c *Client) Build(ctx context.Context, options *pb.BuildOptions, in io.ReadCloser, progress progress.Writer) (string, *client.SolveResponse, *build.Inputs, error) {
ref := identity.NewID() ref := identity.NewID()
statusChan := make(chan *client.SolveStatus) statusChan := make(chan *client.SolveStatus)
eg, egCtx := errgroup.WithContext(ctx) eg, egCtx := errgroup.WithContext(ctx)
@@ -131,10 +134,10 @@ func (c *Client) Build(ctx context.Context, options pb.BuildOptions, in io.ReadC
} }
return nil return nil
}) })
return ref, resp, eg.Wait() return ref, resp, nil, eg.Wait()
} }
func (c *Client) build(ctx context.Context, ref string, options pb.BuildOptions, in io.ReadCloser, statusChan chan *client.SolveStatus) (*client.SolveResponse, error) { func (c *Client) build(ctx context.Context, sessionID string, options *pb.BuildOptions, in io.ReadCloser, statusChan chan *client.SolveStatus) (*client.SolveResponse, error) {
eg, egCtx := errgroup.WithContext(ctx) eg, egCtx := errgroup.WithContext(ctx)
done := make(chan struct{}) done := make(chan struct{})
@@ -143,8 +146,8 @@ func (c *Client) build(ctx context.Context, ref string, options pb.BuildOptions,
eg.Go(func() error { eg.Go(func() error {
defer close(done) defer close(done)
pbResp, err := c.client().Build(egCtx, &pb.BuildRequest{ pbResp, err := c.client().Build(egCtx, &pb.BuildRequest{
Ref: ref, SessionID: sessionID,
Options: &options, Options: options,
}) })
if err != nil { if err != nil {
return err return err
@@ -156,7 +159,7 @@ func (c *Client) build(ctx context.Context, ref string, options pb.BuildOptions,
}) })
eg.Go(func() error { eg.Go(func() error {
stream, err := c.client().Status(egCtx, &pb.StatusRequest{ stream, err := c.client().Status(egCtx, &pb.StatusRequest{
Ref: ref, SessionID: sessionID,
}) })
if err != nil { if err != nil {
return err return err
@@ -181,7 +184,7 @@ func (c *Client) build(ctx context.Context, ref string, options pb.BuildOptions,
if err := stream.Send(&pb.InputMessage{ if err := stream.Send(&pb.InputMessage{
Input: &pb.InputMessage_Init{ Input: &pb.InputMessage_Init{
Init: &pb.InputInitMessage{ Init: &pb.InputInitMessage{
Ref: ref, SessionID: sessionID,
}, },
}, },
}); err != nil { }); err != nil {

View File

@@ -148,8 +148,8 @@ func serveCmd(dockerCli command.Cli) *cobra.Command {
}() }()
// prepare server // prepare server
b := NewServer(func(ctx context.Context, options *controllerapi.BuildOptions, stdin io.Reader, progress progress.Writer) (*client.SolveResponse, *build.ResultHandle, error) { b := NewServer(func(ctx context.Context, options *controllerapi.BuildOptions, stdin io.Reader, progress progress.Writer) (*client.SolveResponse, *build.ResultHandle, *build.Inputs, error) {
return cbuild.RunBuild(ctx, dockerCli, *options, stdin, progress, true) return cbuild.RunBuild(ctx, dockerCli, options, stdin, progress, true)
}) })
defer b.Close() defer b.Close()
@@ -258,7 +258,7 @@ func prepareRootDir(dockerCli command.Cli, config *serverConfig) (string, error)
} }
func rootDataDir(dockerCli command.Cli) string { func rootDataDir(dockerCli command.Cli) string {
return filepath.Join(confutil.ConfigDir(dockerCli), "controller") return filepath.Join(confutil.NewConfig(dockerCli).Dir(), "controller")
} }
func newBuildxClientAndCheck(ctx context.Context, addr string) (*Client, error) { func newBuildxClientAndCheck(ctx context.Context, addr string) (*Client, error) {

View File

@@ -43,9 +43,9 @@ func serveIO(attachCtx context.Context, srv msgStream, initFn func(*pb.InitMessa
if init == nil { if init == nil {
return errors.Errorf("unexpected message: %T; wanted init", msg.GetInput()) return errors.Errorf("unexpected message: %T; wanted init", msg.GetInput())
} }
ref := init.Ref sessionID := init.SessionID
if ref == "" { if sessionID == "" {
return errors.New("no ref is provided") return errors.New("no session ID is provided")
} }
if err := initFn(init); err != nil { if err := initFn(init); err != nil {
return errors.Wrap(err, "failed to initialize IO server") return errors.Wrap(err, "failed to initialize IO server")

View File

@@ -11,6 +11,7 @@ import (
controllererrors "github.com/docker/buildx/controller/errdefs" controllererrors "github.com/docker/buildx/controller/errdefs"
"github.com/docker/buildx/controller/pb" "github.com/docker/buildx/controller/pb"
"github.com/docker/buildx/controller/processes" "github.com/docker/buildx/controller/processes"
"github.com/docker/buildx/util/desktop"
"github.com/docker/buildx/util/ioset" "github.com/docker/buildx/util/ioset"
"github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/progress"
"github.com/docker/buildx/version" "github.com/docker/buildx/version"
@@ -19,7 +20,7 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
type BuildFunc func(ctx context.Context, options *pb.BuildOptions, stdin io.Reader, progress progress.Writer) (resp *client.SolveResponse, res *build.ResultHandle, err error) type BuildFunc func(ctx context.Context, options *pb.BuildOptions, stdin io.Reader, progress progress.Writer) (resp *client.SolveResponse, res *build.ResultHandle, inp *build.Inputs, err error)
func NewServer(buildFunc BuildFunc) *Server { func NewServer(buildFunc BuildFunc) *Server {
return &Server{ return &Server{
@@ -52,9 +53,9 @@ func (s *session) cancelRunningProcesses() {
func (m *Server) ListProcesses(ctx context.Context, req *pb.ListProcessesRequest) (res *pb.ListProcessesResponse, err error) { func (m *Server) ListProcesses(ctx context.Context, req *pb.ListProcessesRequest) (res *pb.ListProcessesResponse, err error) {
m.sessionMu.Lock() m.sessionMu.Lock()
defer m.sessionMu.Unlock() defer m.sessionMu.Unlock()
s, ok := m.session[req.Ref] s, ok := m.session[req.SessionID]
if !ok { if !ok {
return nil, errors.Errorf("unknown ref %q", req.Ref) return nil, errors.Errorf("unknown session ID %q", req.SessionID)
} }
res = new(pb.ListProcessesResponse) res = new(pb.ListProcessesResponse)
res.Infos = append(res.Infos, s.processes.ListProcesses()...) res.Infos = append(res.Infos, s.processes.ListProcesses()...)
@@ -64,9 +65,9 @@ func (m *Server) ListProcesses(ctx context.Context, req *pb.ListProcessesRequest
func (m *Server) DisconnectProcess(ctx context.Context, req *pb.DisconnectProcessRequest) (res *pb.DisconnectProcessResponse, err error) { func (m *Server) DisconnectProcess(ctx context.Context, req *pb.DisconnectProcessRequest) (res *pb.DisconnectProcessResponse, err error) {
m.sessionMu.Lock() m.sessionMu.Lock()
defer m.sessionMu.Unlock() defer m.sessionMu.Unlock()
s, ok := m.session[req.Ref] s, ok := m.session[req.SessionID]
if !ok { if !ok {
return nil, errors.Errorf("unknown ref %q", req.Ref) return nil, errors.Errorf("unknown session ID %q", req.SessionID)
} }
return res, s.processes.DeleteProcess(req.ProcessID) return res, s.processes.DeleteProcess(req.ProcessID)
} }
@@ -100,13 +101,13 @@ func (m *Server) List(ctx context.Context, req *pb.ListRequest) (res *pb.ListRes
} }
func (m *Server) Disconnect(ctx context.Context, req *pb.DisconnectRequest) (res *pb.DisconnectResponse, err error) { func (m *Server) Disconnect(ctx context.Context, req *pb.DisconnectRequest) (res *pb.DisconnectResponse, err error) {
key := req.Ref sessionID := req.SessionID
if key == "" { if sessionID == "" {
return nil, errors.New("disconnect: empty key") return nil, errors.New("disconnect: empty session ID")
} }
m.sessionMu.Lock() m.sessionMu.Lock()
if s, ok := m.session[key]; ok { if s, ok := m.session[sessionID]; ok {
if s.cancelBuild != nil { if s.cancelBuild != nil {
s.cancelBuild() s.cancelBuild()
} }
@@ -115,7 +116,7 @@ func (m *Server) Disconnect(ctx context.Context, req *pb.DisconnectRequest) (res
s.result.Done() s.result.Done()
} }
} }
delete(m.session, key) delete(m.session, sessionID)
m.sessionMu.Unlock() m.sessionMu.Unlock()
return &pb.DisconnectResponse{}, nil return &pb.DisconnectResponse{}, nil
@@ -136,26 +137,26 @@ func (m *Server) Close() error {
} }
func (m *Server) Inspect(ctx context.Context, req *pb.InspectRequest) (*pb.InspectResponse, error) { func (m *Server) Inspect(ctx context.Context, req *pb.InspectRequest) (*pb.InspectResponse, error) {
ref := req.Ref sessionID := req.SessionID
if ref == "" { if sessionID == "" {
return nil, errors.New("inspect: empty key") return nil, errors.New("inspect: empty session ID")
} }
var bo *pb.BuildOptions var bo *pb.BuildOptions
m.sessionMu.Lock() m.sessionMu.Lock()
if s, ok := m.session[ref]; ok { if s, ok := m.session[sessionID]; ok {
bo = s.buildOptions bo = s.buildOptions
} else { } else {
m.sessionMu.Unlock() m.sessionMu.Unlock()
return nil, errors.Errorf("inspect: unknown key %v", ref) return nil, errors.Errorf("inspect: unknown key %v", sessionID)
} }
m.sessionMu.Unlock() m.sessionMu.Unlock()
return &pb.InspectResponse{Options: bo}, nil return &pb.InspectResponse{Options: bo}, nil
} }
func (m *Server) Build(ctx context.Context, req *pb.BuildRequest) (*pb.BuildResponse, error) { func (m *Server) Build(ctx context.Context, req *pb.BuildRequest) (*pb.BuildResponse, error) {
ref := req.Ref sessionID := req.SessionID
if ref == "" { if sessionID == "" {
return nil, errors.New("build: empty key") return nil, errors.New("build: empty session ID")
} }
// Prepare status channel and session // Prepare status channel and session
@@ -163,7 +164,7 @@ func (m *Server) Build(ctx context.Context, req *pb.BuildRequest) (*pb.BuildResp
if m.session == nil { if m.session == nil {
m.session = make(map[string]*session) m.session = make(map[string]*session)
} }
s, ok := m.session[ref] s, ok := m.session[sessionID]
if ok { if ok {
if !s.buildOnGoing.CompareAndSwap(false, true) { if !s.buildOnGoing.CompareAndSwap(false, true) {
m.sessionMu.Unlock() m.sessionMu.Unlock()
@@ -182,12 +183,12 @@ func (m *Server) Build(ctx context.Context, req *pb.BuildRequest) (*pb.BuildResp
inR, inW := io.Pipe() inR, inW := io.Pipe()
defer inR.Close() defer inR.Close()
s.inputPipe = inW s.inputPipe = inW
m.session[ref] = s m.session[sessionID] = s
m.sessionMu.Unlock() m.sessionMu.Unlock()
defer func() { defer func() {
close(statusChan) close(statusChan)
m.sessionMu.Lock() m.sessionMu.Lock()
s, ok := m.session[ref] s, ok := m.session[sessionID]
if ok { if ok {
s.statusChan = nil s.statusChan = nil
s.buildOnGoing.Store(false) s.buildOnGoing.Store(false)
@@ -200,22 +201,27 @@ func (m *Server) Build(ctx context.Context, req *pb.BuildRequest) (*pb.BuildResp
// Build the specified request // Build the specified request
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
resp, res, buildErr := m.buildFunc(ctx, req.Options, inR, pw) resp, res, _, buildErr := m.buildFunc(ctx, req.Options, inR, pw)
m.sessionMu.Lock() m.sessionMu.Lock()
if s, ok := m.session[ref]; ok { if s, ok := m.session[sessionID]; ok {
// NOTE: buildFunc can return *build.ResultHandle even on error (e.g. when it's implemented using (github.com/docker/buildx/controller/build).RunBuild). // NOTE: buildFunc can return *build.ResultHandle even on error (e.g. when it's implemented using (github.com/docker/buildx/controller/build).RunBuild).
if res != nil { if res != nil {
s.result = res s.result = res
s.cancelBuild = cancel s.cancelBuild = cancel
s.buildOptions = req.Options s.buildOptions = req.Options
m.session[ref] = s m.session[sessionID] = s
if buildErr != nil { if buildErr != nil {
buildErr = controllererrors.WrapBuild(buildErr, ref) var ref string
var ebr *desktop.ErrorWithBuildRef
if errors.As(buildErr, &ebr) {
ref = ebr.Ref
}
buildErr = controllererrors.WrapBuild(buildErr, sessionID, ref)
} }
} }
} else { } else {
m.sessionMu.Unlock() m.sessionMu.Unlock()
return nil, errors.Errorf("build: unknown key %v", ref) return nil, errors.Errorf("build: unknown session ID %v", sessionID)
} }
m.sessionMu.Unlock() m.sessionMu.Unlock()
@@ -232,9 +238,9 @@ func (m *Server) Build(ctx context.Context, req *pb.BuildRequest) (*pb.BuildResp
} }
func (m *Server) Status(req *pb.StatusRequest, stream pb.Controller_StatusServer) error { func (m *Server) Status(req *pb.StatusRequest, stream pb.Controller_StatusServer) error {
ref := req.Ref sessionID := req.SessionID
if ref == "" { if sessionID == "" {
return errors.New("status: empty key") return errors.New("status: empty session ID")
} }
// Wait and get status channel prepared by Build() // Wait and get status channel prepared by Build()
@@ -242,12 +248,12 @@ func (m *Server) Status(req *pb.StatusRequest, stream pb.Controller_StatusServer
for { for {
// TODO: timeout? // TODO: timeout?
m.sessionMu.Lock() m.sessionMu.Lock()
if _, ok := m.session[ref]; !ok || m.session[ref].statusChan == nil { if _, ok := m.session[sessionID]; !ok || m.session[sessionID].statusChan == nil {
m.sessionMu.Unlock() m.sessionMu.Unlock()
time.Sleep(time.Millisecond) // TODO: wait Build without busy loop and make it cancellable time.Sleep(time.Millisecond) // TODO: wait Build without busy loop and make it cancellable
continue continue
} }
statusChan = m.session[ref].statusChan statusChan = m.session[sessionID].statusChan
m.sessionMu.Unlock() m.sessionMu.Unlock()
break break
} }
@@ -278,9 +284,9 @@ func (m *Server) Input(stream pb.Controller_InputServer) (err error) {
if init == nil { if init == nil {
return errors.Errorf("unexpected message: %T; wanted init", msg.GetInit()) return errors.Errorf("unexpected message: %T; wanted init", msg.GetInit())
} }
ref := init.Ref sessionID := init.SessionID
if ref == "" { if sessionID == "" {
return errors.New("input: no ref is provided") return errors.New("input: no session ID is provided")
} }
// Wait and get input stream pipe prepared by Build() // Wait and get input stream pipe prepared by Build()
@@ -288,12 +294,12 @@ func (m *Server) Input(stream pb.Controller_InputServer) (err error) {
for { for {
// TODO: timeout? // TODO: timeout?
m.sessionMu.Lock() m.sessionMu.Lock()
if _, ok := m.session[ref]; !ok || m.session[ref].inputPipe == nil { if _, ok := m.session[sessionID]; !ok || m.session[sessionID].inputPipe == nil {
m.sessionMu.Unlock() m.sessionMu.Unlock()
time.Sleep(time.Millisecond) // TODO: wait Build without busy loop and make it cancellable time.Sleep(time.Millisecond) // TODO: wait Build without busy loop and make it cancellable
continue continue
} }
inputPipeW = m.session[ref].inputPipe inputPipeW = m.session[sessionID].inputPipe
m.sessionMu.Unlock() m.sessionMu.Unlock()
break break
} }
@@ -373,14 +379,14 @@ func (m *Server) Invoke(srv pb.Controller_InvokeServer) error {
initErrCh <- retErr initErrCh <- retErr
} }
}() }()
ref := initMessage.Ref sessionID := initMessage.SessionID
cfg := initMessage.InvokeConfig cfg := initMessage.InvokeConfig
m.sessionMu.Lock() m.sessionMu.Lock()
s, ok := m.session[ref] s, ok := m.session[sessionID]
if !ok { if !ok {
m.sessionMu.Unlock() m.sessionMu.Unlock()
return errors.Errorf("invoke: unknown key %v", ref) return errors.Errorf("invoke: unknown session ID %v", sessionID)
} }
m.sessionMu.Unlock() m.sessionMu.Unlock()

View File

@@ -844,7 +844,7 @@ The following example forces the builder to always pull all images referenced in
```hcl ```hcl
target "default" { target "default" {
pull = "always" pull = true
} }
``` ```
@@ -871,8 +871,8 @@ This lets you [mount the secret][run_mount_secret] in your Dockerfile.
```dockerfile ```dockerfile
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \ RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
aws cloudfront create-invalidation ... aws cloudfront create-invalidation ...
RUN --mount=type=secret,id=KUBECONFIG \ RUN --mount=type=secret,id=KUBECONFIG,env=KUBECONFIG \
KUBECONFIG=$(cat /run/secrets/KUBECONFIG) helm upgrade --install helm upgrade --install
``` ```
### `target.shm-size` ### `target.shm-size`

View File

@@ -626,7 +626,7 @@ For example, the following Dockerfile contains four stages:
```dockerfile ```dockerfile
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM oven/bun:1 as base FROM oven/bun:1 AS base
WORKDIR /app WORKDIR /app
FROM base AS install FROM base AS install
@@ -912,17 +912,39 @@ For more information about how to use build secrets, see
Supported types are: Supported types are:
- [`file`](#file) - [`type=file`](#typefile)
- [`env`](#env) - [`type=env`](#typeenv)
Buildx attempts to detect the `type` automatically if unset. Buildx attempts to detect the `type` automatically if unset. If an environment
variable with the same key as `id` is set, then Buildx uses `type=env` and the
variable value becomes the secret. If no such environment variable is set, and
`type` is not set, then Buildx falls back to `type=file`.
#### `file` #### `type=file`
Attribute keys: Source a build secret from a file.
- `id` - ID of the secret. Defaults to base name of the `src` path. ##### `type=file` synopsis
- `src`, `source` - Secret filename. `id` used if unset.
```console
$ docker buildx build --secret [type=file,]id=<ID>[,src=<FILEPATH>] .
```
##### `type=file` attributes
| Key | Description | Default |
| --------------- | ----------------------------------------------------------------------------------------------------- | -------------------------- |
| `id` | ID of the secret. | N/A (this key is required) |
| `src`, `source` | Filepath of the file containing the secret value (absolute or relative to current working directory). | `id` if unset. |
###### `type=file` usage
In the following example, `type=file` is automatically detected because no
environment variable mathing `aws` (the ID) is set.
```console
$ docker buildx build --secret id=aws,src=$HOME/.aws/credentials .
```
```dockerfile ```dockerfile
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
@@ -932,29 +954,60 @@ RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
aws s3 cp s3://... ... aws s3 cp s3://... ...
``` ```
#### `type=env`
Source a build secret from an environment variable.
##### `type=env` synopsis
```console ```console
$ docker buildx build --secret id=aws,src=$HOME/.aws/credentials . $ docker buildx build --secret [type=env,]id=<ID>[,env=<VARIABLE>] .
``` ```
#### `env` ##### `type=env` attributes
Attribute keys: | Key | Description | Default |
| ---------------------- | ----------------------------------------------- | -------------------------- |
| `id` | ID of the secret. | N/A (this key is required) |
| `env`, `src`, `source` | Environment variable to source the secret from. | `id` if unset. |
- `id` - ID of the secret. Defaults to `env` name. ##### `type=env` usage
- `env` - Secret environment variable. `id` used if unset, otherwise will look for `src`, `source` if `id` unset.
In the following example, `type=env` is automatically detected because an
environment variable matching `id` is set.
```console
$ SECRET_TOKEN=token docker buildx build --secret id=SECRET_TOKEN .
```
```dockerfile ```dockerfile
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM node:alpine FROM node:alpine
RUN --mount=type=bind,target=. \ RUN --mount=type=bind,target=. \
--mount=type=secret,id=SECRET_TOKEN \ --mount=type=secret,id=SECRET_TOKEN,env=SECRET_TOKEN \
SECRET_TOKEN=$(cat /run/secrets/SECRET_TOKEN) yarn run test yarn run test
``` ```
In the following example, the build argument `SECRET_TOKEN` is set to contain
the value of the environment variable `API_KEY`.
```console ```console
$ SECRET_TOKEN=token docker buildx build --secret id=SECRET_TOKEN . $ API_KEY=token docker buildx build --secret id=SECRET_TOKEN,env=API_KEY .
``` ```
You can also specify the name of the environment variable with `src` or `source`:
```console
$ API_KEY=token docker buildx build --secret type=env,id=SECRET_TOKEN,src=API_KEY .
```
> [!NOTE]
> Specifying the environment variable name with `src` or `source`, you are
> required to set `type=env` explicitly, or else Buildx assumes that the secret
> is `type=file`, and looks for a file with the name of `src` or `source` (in
> this case, a file named `API_KEY` relative to the location where the `docker
> buildx build` command was executed.
### <a name="shm-size"></a> Shared memory size for build containers (--shm-size) ### <a name="shm-size"></a> Shared memory size for build containers (--shm-size)
Sets the size of the shared memory allocated for build containers when using Sets the size of the shared memory allocated for build containers when using

View File

@@ -9,10 +9,11 @@ List builder instances
### Options ### Options
| Name | Type | Default | Description | | Name | Type | Default | Description |
|:----------------------|:---------|:--------|:---------------------| |:----------------------|:---------|:--------|:----------------------|
| `-D`, `--debug` | `bool` | | Enable debug logging | | `-D`, `--debug` | `bool` | | Enable debug logging |
| [`--format`](#format) | `string` | `table` | Format the output | | [`--format`](#format) | `string` | `table` | Format the output |
| `--no-trunc` | `bool` | | Don't truncate output |
<!---MARKER_GEN_END--> <!---MARKER_GEN_END-->

View File

@@ -9,15 +9,17 @@ Remove build cache
### Options ### Options
| Name | Type | Default | Description | | Name | Type | Default | Description |
|:------------------------|:---------|:--------|:------------------------------------------| |:------------------------|:---------|:--------|:-------------------------------------------------------|
| `-a`, `--all` | `bool` | | Include internal/frontend images | | `-a`, `--all` | `bool` | | Include internal/frontend images |
| [`--builder`](#builder) | `string` | | Override the configured builder instance | | [`--builder`](#builder) | `string` | | Override the configured builder instance |
| `-D`, `--debug` | `bool` | | Enable debug logging | | `-D`, `--debug` | `bool` | | Enable debug logging |
| `--filter` | `filter` | | Provide filter values (e.g., `until=24h`) | | `--filter` | `filter` | | Provide filter values (e.g., `until=24h`) |
| `-f`, `--force` | `bool` | | Do not prompt for confirmation | | `-f`, `--force` | `bool` | | Do not prompt for confirmation |
| `--keep-storage` | `bytes` | `0` | Amount of disk space to keep for cache | | `--max-used-space` | `bytes` | `0` | Maximum amount of disk space allowed to keep for cache |
| `--verbose` | `bool` | | Provide a more verbose output | | `--min-free-space` | `bytes` | `0` | Target amount of free disk space after pruning |
| `--reserved-space` | `bytes` | `0` | Amount of disk space always allowed to keep for cache |
| `--verbose` | `bool` | | Provide a more verbose output |
<!---MARKER_GEN_END--> <!---MARKER_GEN_END-->

65
go.mod
View File

@@ -1,35 +1,33 @@
module github.com/docker/buildx module github.com/docker/buildx
go 1.21.0 go 1.22.0
require ( require (
github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/semver/v3 v3.2.1
github.com/Microsoft/go-winio v0.6.2 github.com/Microsoft/go-winio v0.6.2
github.com/aws/aws-sdk-go-v2/config v1.26.6 github.com/aws/aws-sdk-go-v2/config v1.26.6
github.com/compose-spec/compose-go/v2 v2.1.6 github.com/compose-spec/compose-go/v2 v2.2.0
github.com/containerd/console v1.0.4 github.com/containerd/console v1.0.4
github.com/containerd/containerd v1.7.20 github.com/containerd/containerd v1.7.22
github.com/containerd/continuity v0.4.3 github.com/containerd/continuity v0.4.4
github.com/containerd/errdefs v0.1.0 github.com/containerd/errdefs v0.1.0
github.com/containerd/log v0.1.0 github.com/containerd/log v0.1.0
github.com/containerd/platforms v0.2.1 github.com/containerd/platforms v0.2.1
github.com/containerd/typeurl/v2 v2.2.0 github.com/containerd/typeurl/v2 v2.2.0
github.com/creack/pty v1.1.21 github.com/creack/pty v1.1.21
github.com/distribution/reference v0.6.0 github.com/distribution/reference v0.6.0
github.com/docker/cli v27.2.0+incompatible github.com/docker/cli v27.3.1+incompatible
github.com/docker/cli-docs-tool v0.8.0 github.com/docker/cli-docs-tool v0.8.0
github.com/docker/docker v27.2.0+incompatible github.com/docker/docker v27.3.1+incompatible
github.com/docker/go-units v0.5.0 github.com/docker/go-units v0.5.0
github.com/gofrs/flock v0.12.1 github.com/gofrs/flock v0.12.1
github.com/gogo/protobuf v1.3.2
github.com/golang/protobuf v1.5.4
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992 github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992
github.com/hashicorp/hcl/v2 v2.20.1 github.com/hashicorp/hcl/v2 v2.20.1
github.com/in-toto/in-toto-golang v0.5.0 github.com/in-toto/in-toto-golang v0.5.0
github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/moby/buildkit v0.16.0-rc1 github.com/moby/buildkit v0.17.0-rc2
github.com/moby/sys/mountinfo v0.7.2 github.com/moby/sys/mountinfo v0.7.2
github.com/moby/sys/signal v0.7.1 github.com/moby/sys/signal v0.7.1
github.com/morikuni/aec v1.0.0 github.com/morikuni/aec v1.0.0
@@ -37,24 +35,27 @@ require (
github.com/opencontainers/image-spec v1.1.0 github.com/opencontainers/image-spec v1.1.0
github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml v1.9.5
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.1 github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c github.com/tonistiigi/fsutil v0.0.0-20241028165955-397af5306b5c
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4
github.com/zclconf/go-cty v1.14.4 github.com/zclconf/go-cty v1.14.4
go.opentelemetry.io/otel v1.21.0 go.opentelemetry.io/otel v1.21.0
go.opentelemetry.io/otel/metric v1.21.0 go.opentelemetry.io/otel/metric v1.21.0
go.opentelemetry.io/otel/sdk v1.21.0 go.opentelemetry.io/otel/sdk v1.21.0
go.opentelemetry.io/otel/trace v1.21.0 go.opentelemetry.io/otel/trace v1.21.0
golang.org/x/mod v0.17.0 golang.org/x/mod v0.21.0
golang.org/x/sync v0.7.0 golang.org/x/sync v0.8.0
golang.org/x/sys v0.22.0 golang.org/x/sys v0.26.0
golang.org/x/term v0.20.0 golang.org/x/term v0.24.0
golang.org/x/text v0.15.0 golang.org/x/text v0.18.0
google.golang.org/grpc v1.60.1 google.golang.org/grpc v1.66.2
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1
google.golang.org/protobuf v1.35.1
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.29.2 k8s.io/api v0.29.2
k8s.io/apimachinery v0.29.2 k8s.io/apimachinery v0.29.2
@@ -82,10 +83,10 @@ require (
github.com/aws/smithy-go v1.19.0 // indirect github.com/aws/smithy-go v1.19.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/containerd/api v1.7.19 // indirect github.com/containerd/containerd/api v1.7.19 // indirect
github.com/containerd/ttrpc v1.2.5 // indirect github.com/containerd/ttrpc v1.2.5 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect
@@ -101,7 +102,8 @@ require (
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect github.com/google/gofuzz v1.2.0 // indirect
@@ -115,7 +117,7 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/compress v1.17.11 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect
@@ -127,7 +129,7 @@ require (
github.com/moby/locker v1.0.1 // indirect github.com/moby/locker v1.0.1 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.3.0 // indirect github.com/moby/sys/user v0.3.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.0 // indirect github.com/moby/term v0.5.0 // indirect
@@ -145,6 +147,7 @@ require (
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/theupdateframework/notary v0.7.0 // indirect github.com/theupdateframework/notary v0.7.0 // indirect
github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205 // indirect
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab // indirect github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
@@ -160,17 +163,15 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.21.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.21.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect
golang.org/x/crypto v0.23.0 // indirect golang.org/x/crypto v0.27.0 // indirect
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.29.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.17.0 // indirect golang.org/x/tools v0.25.0 // indirect
google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.110.1 // indirect k8s.io/klog/v2 v2.110.1 // indirect

163
go.sum
View File

@@ -1,8 +1,7 @@
cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA=
@@ -15,8 +14,8 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ= github.com/Microsoft/hcsshim v0.12.5 h1:bpTInLlDy/nDRWFVcefDZZ1+U8tS+rz3MxjKgu9boo0=
github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= github.com/Microsoft/hcsshim v0.12.5/go.mod h1:tIUGego4G1EN5Hb6KC90aDYiUI2dqLSTTOCjVNpOgZ8=
github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
@@ -76,26 +75,27 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXe
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ= github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ=
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
github.com/compose-spec/compose-go/v2 v2.1.6 h1:d0Cs0DffmOwmSzs0YPHwKCskknGq2jfGg4uGowlEpps= github.com/compose-spec/compose-go/v2 v2.2.0 h1:VsQosGhuO+H9wh5laiIiAe4TVd73kQ5NWwmNrdm0HRA=
github.com/compose-spec/compose-go/v2 v2.1.6/go.mod h1:lFN0DrMxIncJGYAXTfWuajfwj5haBJqrBkarHcnjJKc= github.com/compose-spec/compose-go/v2 v2.2.0/go.mod h1:lFN0DrMxIncJGYAXTfWuajfwj5haBJqrBkarHcnjJKc=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0=
github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE=
github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/containerd/containerd v1.7.20 h1:Sl6jQYk3TRavaU83h66QMbI2Nqg9Jm6qzwX57Vsn1SQ= github.com/containerd/containerd v1.7.22 h1:nZuNnNRA6T6jB975rx2RRNqqH2k6ELYKDZfqTHqwyy0=
github.com/containerd/containerd v1.7.20/go.mod h1:52GsS5CwquuqPuLncsXwG0t2CiUce+KsNHJZQJvAgR0= github.com/containerd/containerd v1.7.22/go.mod h1:e3Jz1rYRUZ2Lt51YrH9Rz0zPyJBOlSvB3ghr2jbVD8g=
github.com/containerd/containerd/api v1.7.19 h1:VWbJL+8Ap4Ju2mx9c9qS1uFSB1OVYr5JJrW2yT5vFoA= github.com/containerd/containerd/api v1.7.19 h1:VWbJL+8Ap4Ju2mx9c9qS1uFSB1OVYr5JJrW2yT5vFoA=
github.com/containerd/containerd/api v1.7.19/go.mod h1:fwGavl3LNwAV5ilJ0sbrABL44AQxmNjDRcwheXDb6Ig= github.com/containerd/containerd/api v1.7.19/go.mod h1:fwGavl3LNwAV5ilJ0sbrABL44AQxmNjDRcwheXDb6Ig=
github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= github.com/containerd/continuity v0.4.4 h1:/fNVfTJ7wIl/YPMHjf+5H32uFhl63JucB34PlCpMKII=
github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM= github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0= github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0=
github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
@@ -113,8 +113,9 @@ github.com/containerd/ttrpc v1.2.5 h1:IFckT1EFQoFBMG4c3sMdT8EP3/aKfumK1msY+Ze4oL
github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o=
github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso= github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso=
github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g= github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
@@ -124,15 +125,15 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v27.2.0+incompatible h1:yHD1QEB1/0vr5eBNpu8tncu8gWxg8EydFPOSKHzXSMM= github.com/docker/cli v27.3.1+incompatible h1:qEGdFBF3Xu6SCvCYhc7CzaQTlBmqDuzxPDpigSyeKQQ=
github.com/docker/cli v27.2.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v27.3.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli-docs-tool v0.8.0 h1:YcDWl7rQJC3lJ7WVZRwSs3bc9nka97QLWfyJQli8yJU= github.com/docker/cli-docs-tool v0.8.0 h1:YcDWl7rQJC3lJ7WVZRwSs3bc9nka97QLWfyJQli8yJU=
github.com/docker/cli-docs-tool v0.8.0/go.mod h1:8TQQ3E7mOXoYUs811LiPdUnAhXrcVsBIrW21a5pUbdk= github.com/docker/cli-docs-tool v0.8.0/go.mod h1:8TQQ3E7mOXoYUs811LiPdUnAhXrcVsBIrW21a5pUbdk=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4= github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
@@ -152,8 +153,8 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNE
github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
@@ -186,15 +187,13 @@ github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAp
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -202,8 +201,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93 h1:jc2UWq7CbdszqeH6qu1ougXMIUBfSy8Pbh/anURYbGI= github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93 h1:jc2UWq7CbdszqeH6qu1ougXMIUBfSy8Pbh/anURYbGI=
@@ -212,7 +209,6 @@ github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvR
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -270,8 +266,8 @@ github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVE
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -307,8 +303,8 @@ github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/z
github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/buildkit v0.16.0-rc1 h1:G6KBYr6T4B1ylpinYIjcNLcVkPUkuddw3daqaM9yg9A= github.com/moby/buildkit v0.17.0-rc2 h1:+L7qAYuBEA9D7IBTEYdzFf4SsC7JBEOcAG8oRVrzveA=
github.com/moby/buildkit v0.16.0-rc1/go.mod h1:WLr3pMBXsAoSuZIGdGww1JPz8S8Qp+OTf0dlrPnzbDg= github.com/moby/buildkit v0.17.0-rc2/go.mod h1:ru8NFyDHD8HbuKaLXJIjK9nr3x6FZR+IWjtF07S+wdM=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
@@ -319,8 +315,8 @@ github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0= github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8= github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8=
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
@@ -371,6 +367,8 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -443,8 +441,10 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c= github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw= github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c h1:+6wg/4ORAbnSoGDzg2Q1i3CeMcT/jjhye/ZfnBHy7/M= github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205 h1:eUk79E1w8yMtXeHSzjKorxuC8qJOnyXQnLaJehxpJaI=
github.com/tonistiigi/fsutil v0.0.0-20240424095704-91a3fc46842c/go.mod h1:vbbYqJlnswsbJqWUcJN8fKtBhnEgldDrcagTgnBVKKM= github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205/go.mod h1:3Iuxbr0P7D3zUzBMAZB+ois3h/et0shEz0qApgHYGpY=
github.com/tonistiigi/fsutil v0.0.0-20241028165955-397af5306b5c h1:bQLsfX+uEPZUjyR2qmoJs5F8Z57bPVmF3IsUf22Xo9Y=
github.com/tonistiigi/fsutil v0.0.0-20241028165955-397af5306b5c/go.mod h1:Dl/9oEjK7IqnjAm21Okx/XIxUCFJzvh+XdVHUlBwXTw=
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 h1:7I5c2Ig/5FgqkYOh/N87NzoyI9U15qUPXhDD8uCupv8= github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 h1:7I5c2Ig/5FgqkYOh/N87NzoyI9U15qUPXhDD8uCupv8=
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4/go.mod h1:278M4p8WsNh3n4a1eqiFcV2FGk7wE5fwUpUom9mK9lE= github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4/go.mod h1:278M4p8WsNh3n4a1eqiFcV2FGk7wE5fwUpUom9mK9lE=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0= github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0=
@@ -463,7 +463,6 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ= github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
@@ -509,16 +508,14 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200422194213-44a606286825/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200422194213-44a606286825/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -526,21 +523,18 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -550,56 +544,45 @@ golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.3.0/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.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg= google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo=
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f h1:2yNACc1O40tTnrsbk9Cv6oxiW8pxI/pXj0wRtdlYmgY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 h1:/jFB8jK5R3Sq3i/lmeZO0cATSzFfZaJq1J2Euan3XKU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA=
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII= gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=

View File

@@ -1,20 +1,21 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM alpine:3.14 AS gen ARG ALPINE_VERSION=3.20
FROM alpine:${ALPINE_VERSION} AS gen
RUN apk add --no-cache git RUN apk add --no-cache git
WORKDIR /src WORKDIR /src
RUN --mount=type=bind,target=. <<EOT RUN --mount=type=bind,target=. <<EOT
#!/usr/bin/env bash set -e
set -e mkdir /out
mkdir /out # see also ".mailmap" for how email addresses and names are deduplicated
# see also ".mailmap" for how email addresses and names are deduplicated {
{ echo "# This file lists all individuals having contributed content to the repository."
echo "# This file lists all individuals having contributed content to the repository." echo "# For how it is generated, see hack/dockerfiles/authors.Dockerfile."
echo "# For how it is generated, see hack/dockerfiles/authors.Dockerfile." echo
echo git log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf
git log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf } > /out/AUTHORS
} > /out/AUTHORS cat /out/AUTHORS
cat /out/AUTHORS
EOT EOT
FROM scratch AS update FROM scratch AS update
@@ -22,12 +23,12 @@ COPY --from=gen /out /
FROM gen AS validate FROM gen AS validate
RUN --mount=type=bind,target=.,rw <<EOT RUN --mount=type=bind,target=.,rw <<EOT
set -e set -e
git add -A git add -A
cp -rf /out/* . cp -rf /out/* .
if [ -n "$(git status --porcelain -- AUTHORS)" ]; then if [ -n "$(git status --porcelain -- AUTHORS)" ]; then
echo >&2 'ERROR: Authors result differs. Please update with "make authors"' echo >&2 'ERROR: Authors result differs. Please update with "make authors"'
git status --porcelain -- AUTHORS git status --porcelain -- AUTHORS
exit 1 exit 1
fi fi
EOT EOT

View File

@@ -7,10 +7,13 @@
ARG GO_VERSION="1.22" ARG GO_VERSION="1.22"
ARG PROTOC_VERSION="3.11.4" ARG PROTOC_VERSION="3.11.4"
ARG PROTOC_GOOGLEAPIS_VERSION=2af421884dd468d565137215c946ebe4e245ae26
# protoc is dynamically linked to glibc so can't use alpine base # protoc is dynamically linked to glibc so can't use alpine base
FROM golang:${GO_VERSION}-bookworm AS base FROM golang:${GO_VERSION}-bookworm AS base
RUN apt-get update && apt-get --no-install-recommends install -y git unzip RUN apt-get update && apt-get --no-install-recommends install -y git unzip
FROM base AS protoc
ARG PROTOC_VERSION ARG PROTOC_VERSION
ARG TARGETOS ARG TARGETOS
ARG TARGETARCH ARG TARGETARCH
@@ -18,34 +21,69 @@ RUN <<EOT
set -e set -e
arch=$(echo $TARGETARCH | sed -e s/amd64/x86_64/ -e s/arm64/aarch_64/) arch=$(echo $TARGETARCH | sed -e s/amd64/x86_64/ -e s/arm64/aarch_64/)
wget -q https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-${TARGETOS}-${arch}.zip wget -q https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-${TARGETOS}-${arch}.zip
unzip protoc-${PROTOC_VERSION}-${TARGETOS}-${arch}.zip -d /usr/local unzip protoc-${PROTOC_VERSION}-${TARGETOS}-${arch}.zip -d /opt/protoc
EOT EOT
WORKDIR /go/src/github.com/docker/buildx
FROM base AS tools FROM base AS googleapis
RUN --mount=type=bind,target=.,rw \ ARG PROTOC_GOOGLEAPIS_VERSION
RUN <<EOT
set -e
wget -q https://github.com/googleapis/googleapis/archive/${PROTOC_GOOGLEAPIS_VERSION}.zip -O googleapis.zip
unzip googleapis.zip '*.proto' -d /opt
mkdir -p /opt/googleapis
mv /opt/googleapis-${PROTOC_GOOGLEAPIS_VERSION} /opt/googleapis/include
EOT
FROM base AS gobuild-base
WORKDIR /app
FROM gobuild-base AS vtprotobuf
RUN --mount=type=bind,source=go.mod,target=/app/go.mod \
--mount=type=bind,source=go.sum,target=/app/go.sum \
--mount=type=cache,target=/root/.cache \
--mount=type=cache,target=/go/pkg/mod <<EOT
set -e
mkdir -p /opt/vtprotobuf
go mod download github.com/planetscale/vtprotobuf
cp -r $(go list -m -f='{{.Dir}}' github.com/planetscale/vtprotobuf)/include /opt/vtprotobuf
EOT
FROM gobuild-base AS vendored
RUN --mount=type=bind,source=vendor,target=/app <<EOT
set -e
mkdir -p /opt/vendored/include
find . -name '*.proto' | tar -cf - --files-from - | tar -C /opt/vendored/include -xf -
EOT
FROM gobuild-base AS tools
RUN --mount=type=bind,source=go.mod,target=/app/go.mod,ro \
--mount=type=bind,source=go.sum,target=/app/go.sum,ro \
--mount=type=cache,target=/root/.cache \ --mount=type=cache,target=/root/.cache \
--mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/go/pkg/mod \
go install \ go install \
github.com/gogo/protobuf/protoc-gen-gogo \ github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto \
github.com/gogo/protobuf/protoc-gen-gogofaster \ google.golang.org/protobuf/cmd/protoc-gen-go \
github.com/gogo/protobuf/protoc-gen-gogoslick \ google.golang.org/grpc/cmd/protoc-gen-go-grpc
github.com/golang/protobuf/protoc-gen-go COPY --link --from=protoc /opt/protoc /usr/local
COPY --link --from=googleapis /opt/googleapis /usr/local
COPY --link --from=vtprotobuf /opt/vtprotobuf /usr/local
COPY --link --from=vendored /opt/vendored /usr/local
FROM tools AS generated FROM tools AS generated
RUN --mount=type=bind,target=.,rw <<EOT RUN --mount=type=bind,target=github.com/docker/buildx,ro <<EOT
set -ex set -ex
go generate -mod=vendor -v ./...
mkdir /out mkdir /out
git ls-files -m --others -- ':!vendor' '**/*.pb.go' | tar -cf - --files-from - | tar -C /out -xf - find github.com/docker/buildx -name '*.proto' -o -name vendor -prune -false | xargs \
protoc --go_out=/out --go-grpc_out=require_unimplemented_servers=false:/out \
--go-vtproto_out=features=marshal+unmarshal+size+equal+pool+clone:/out
EOT EOT
FROM scratch AS update FROM scratch AS update
COPY --from=generated /out / COPY --from=generated /out/github.com/docker/buildx /
FROM base AS validate FROM gobuild-base AS validate
RUN --mount=type=bind,target=.,rw \ RUN --mount=type=bind,target=.,rw \
--mount=type=bind,from=generated,source=/out,target=/generated-files <<EOT --mount=type=bind,from=update,target=/generated-files <<EOT
set -e set -e
git add -A git add -A
if [ "$(ls -A /generated-files)" ]; then if [ "$(ls -A /generated-files)" ]; then

View File

@@ -8,7 +8,7 @@ import (
"path/filepath" "path/filepath"
"sync" "sync"
"github.com/docker/docker/pkg/ioutils" "github.com/docker/buildx/util/confutil"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
@@ -42,18 +42,18 @@ type StateGroup struct {
} }
type LocalState struct { type LocalState struct {
root string cfg *confutil.Config
} }
func New(root string) (*LocalState, error) { func New(cfg *confutil.Config) (*LocalState, error) {
if root == "" { if cfg.Dir() == "" {
return nil, errors.Errorf("root dir empty") return nil, errors.Errorf("config dir empty")
} }
if err := os.MkdirAll(filepath.Join(root, refsDir), 0700); err != nil { if err := cfg.MkdirAll(refsDir, 0700); err != nil {
return nil, err return nil, err
} }
return &LocalState{ return &LocalState{
root: root, cfg: cfg,
}, nil }, nil
} }
@@ -61,7 +61,7 @@ func (ls *LocalState) ReadRef(builderName, nodeName, id string) (*State, error)
if err := ls.validate(builderName, nodeName, id); err != nil { if err := ls.validate(builderName, nodeName, id); err != nil {
return nil, err return nil, err
} }
dt, err := os.ReadFile(filepath.Join(ls.root, refsDir, builderName, nodeName, id)) dt, err := os.ReadFile(filepath.Join(ls.cfg.Dir(), refsDir, builderName, nodeName, id))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -76,19 +76,19 @@ func (ls *LocalState) SaveRef(builderName, nodeName, id string, st State) error
if err := ls.validate(builderName, nodeName, id); err != nil { if err := ls.validate(builderName, nodeName, id); err != nil {
return err return err
} }
refDir := filepath.Join(ls.root, refsDir, builderName, nodeName) refDir := filepath.Join(refsDir, builderName, nodeName)
if err := os.MkdirAll(refDir, 0700); err != nil { if err := ls.cfg.MkdirAll(refDir, 0700); err != nil {
return err return err
} }
dt, err := json.Marshal(st) dt, err := json.Marshal(st)
if err != nil { if err != nil {
return err return err
} }
return ioutils.AtomicWriteFile(filepath.Join(refDir, id), dt, 0600) return ls.cfg.AtomicWriteFile(filepath.Join(refDir, id), dt, 0644)
} }
func (ls *LocalState) ReadGroup(id string) (*StateGroup, error) { func (ls *LocalState) ReadGroup(id string) (*StateGroup, error) {
dt, err := os.ReadFile(filepath.Join(ls.root, refsDir, groupDir, id)) dt, err := os.ReadFile(filepath.Join(ls.cfg.Dir(), refsDir, groupDir, id))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -100,15 +100,15 @@ func (ls *LocalState) ReadGroup(id string) (*StateGroup, error) {
} }
func (ls *LocalState) SaveGroup(id string, stg StateGroup) error { func (ls *LocalState) SaveGroup(id string, stg StateGroup) error {
refDir := filepath.Join(ls.root, refsDir, groupDir) refDir := filepath.Join(refsDir, groupDir)
if err := os.MkdirAll(refDir, 0700); err != nil { if err := ls.cfg.MkdirAll(refDir, 0700); err != nil {
return err return err
} }
dt, err := json.Marshal(stg) dt, err := json.Marshal(stg)
if err != nil { if err != nil {
return err return err
} }
return ioutils.AtomicWriteFile(filepath.Join(refDir, id), dt, 0600) return ls.cfg.AtomicWriteFile(filepath.Join(refDir, id), dt, 0600)
} }
func (ls *LocalState) RemoveBuilder(builderName string) error { func (ls *LocalState) RemoveBuilder(builderName string) error {
@@ -116,7 +116,7 @@ func (ls *LocalState) RemoveBuilder(builderName string) error {
return errors.Errorf("builder name empty") return errors.Errorf("builder name empty")
} }
dir := filepath.Join(ls.root, refsDir, builderName) dir := filepath.Join(ls.cfg.Dir(), refsDir, builderName)
if _, err := os.Lstat(dir); err != nil { if _, err := os.Lstat(dir); err != nil {
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
return err return err
@@ -147,7 +147,7 @@ func (ls *LocalState) RemoveBuilderNode(builderName string, nodeName string) err
return errors.Errorf("node name empty") return errors.Errorf("node name empty")
} }
dir := filepath.Join(ls.root, refsDir, builderName, nodeName) dir := filepath.Join(ls.cfg.Dir(), refsDir, builderName, nodeName)
if _, err := os.Lstat(dir); err != nil { if _, err := os.Lstat(dir); err != nil {
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
return err return err
@@ -208,7 +208,7 @@ func (ls *LocalState) removeGroup(id string) error {
if id == "" { if id == "" {
return errors.Errorf("group ref empty") return errors.Errorf("group ref empty")
} }
f := filepath.Join(ls.root, refsDir, groupDir, id) f := filepath.Join(ls.cfg.Dir(), refsDir, groupDir, id)
if _, err := os.Lstat(f); err != nil { if _, err := os.Lstat(f); err != nil {
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
return err return err

View File

@@ -4,6 +4,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/docker/buildx/util/confutil"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -39,10 +40,10 @@ func newls(t *testing.T) *LocalState {
t.Helper() t.Helper()
tmpdir := t.TempDir() tmpdir := t.TempDir()
l, err := New(tmpdir) l, err := New(confutil.NewConfig(nil, confutil.WithDir(tmpdir)))
require.NoError(t, err) require.NoError(t, err)
require.DirExists(t, filepath.Join(tmpdir, refsDir)) require.DirExists(t, filepath.Join(tmpdir, refsDir))
require.Equal(t, tmpdir, l.root) require.Equal(t, tmpdir, l.cfg.Dir())
require.NoError(t, l.SaveRef(testBuilderName, testNodeName, testStateRefID, testStateRef)) require.NoError(t, l.SaveRef(testBuilderName, testNodeName, testStateRefID, testStateRef))

View File

@@ -13,11 +13,11 @@ import (
type ExecCmd struct { type ExecCmd struct {
m types.Monitor m types.Monitor
invokeConfig controllerapi.InvokeConfig invokeConfig *controllerapi.InvokeConfig
stdout io.WriteCloser stdout io.WriteCloser
} }
func NewExecCmd(m types.Monitor, invokeConfig controllerapi.InvokeConfig, stdout io.WriteCloser) types.Command { func NewExecCmd(m types.Monitor, invokeConfig *controllerapi.InvokeConfig, stdout io.WriteCloser) types.Command {
return &ExecCmd{m, invokeConfig, stdout} return &ExecCmd{m, invokeConfig, stdout}
} }
@@ -41,7 +41,7 @@ func (cm *ExecCmd) Exec(ctx context.Context, args []string) error {
if len(args) < 2 { if len(args) < 2 {
return errors.Errorf("command must be passed") return errors.Errorf("command must be passed")
} }
cfg := controllerapi.InvokeConfig{ cfg := &controllerapi.InvokeConfig{
Entrypoint: []string{args[1]}, Entrypoint: []string{args[1]},
Cmd: args[2:], Cmd: args[2:],
NoCmd: false, NoCmd: false,

View File

@@ -20,10 +20,10 @@ type ReloadCmd struct {
progress *progress.Printer progress *progress.Printer
options *controllerapi.BuildOptions options *controllerapi.BuildOptions
invokeConfig controllerapi.InvokeConfig invokeConfig *controllerapi.InvokeConfig
} }
func NewReloadCmd(m types.Monitor, stdout io.WriteCloser, progress *progress.Printer, options *controllerapi.BuildOptions, invokeConfig controllerapi.InvokeConfig) types.Command { func NewReloadCmd(m types.Monitor, stdout io.WriteCloser, progress *progress.Printer, options *controllerapi.BuildOptions, invokeConfig *controllerapi.InvokeConfig) types.Command {
return &ReloadCmd{m, stdout, progress, options, invokeConfig} return &ReloadCmd{m, stdout, progress, options, invokeConfig}
} }
@@ -61,7 +61,7 @@ func (cm *ReloadCmd) Exec(ctx context.Context, args []string) error {
} }
var resultUpdated bool var resultUpdated bool
cm.progress.Unpause() cm.progress.Unpause()
ref, _, err := cm.m.Build(ctx, *bo, nil, cm.progress) // TODO: support stdin, hold build ref ref, _, _, err := cm.m.Build(ctx, bo, nil, cm.progress) // TODO: support stdin, hold build ref
cm.progress.Pause() cm.progress.Pause()
if err != nil { if err != nil {
var be *controllererrors.BuildError var be *controllererrors.BuildError

View File

@@ -13,11 +13,11 @@ import (
type RollbackCmd struct { type RollbackCmd struct {
m types.Monitor m types.Monitor
invokeConfig controllerapi.InvokeConfig invokeConfig *controllerapi.InvokeConfig
stdout io.WriteCloser stdout io.WriteCloser
} }
func NewRollbackCmd(m types.Monitor, invokeConfig controllerapi.InvokeConfig, stdout io.WriteCloser) types.Command { func NewRollbackCmd(m types.Monitor, invokeConfig *controllerapi.InvokeConfig, stdout io.WriteCloser) types.Command {
return &RollbackCmd{m, invokeConfig, stdout} return &RollbackCmd{m, invokeConfig, stdout}
} }

View File

@@ -10,6 +10,7 @@ import (
"text/tabwriter" "text/tabwriter"
"github.com/containerd/console" "github.com/containerd/console"
"github.com/docker/buildx/build"
"github.com/docker/buildx/controller/control" "github.com/docker/buildx/controller/control"
controllerapi "github.com/docker/buildx/controller/pb" controllerapi "github.com/docker/buildx/controller/pb"
"github.com/docker/buildx/monitor/commands" "github.com/docker/buildx/monitor/commands"
@@ -30,7 +31,7 @@ type MonitorBuildResult struct {
} }
// RunMonitor provides an interactive session for running and managing containers via specified IO. // RunMonitor provides an interactive session for running and managing containers via specified IO.
func RunMonitor(ctx context.Context, curRef string, options *controllerapi.BuildOptions, invokeConfig controllerapi.InvokeConfig, c control.BuildxController, stdin io.ReadCloser, stdout io.WriteCloser, stderr console.File, progress *progress.Printer) (*MonitorBuildResult, error) { func RunMonitor(ctx context.Context, curRef string, options *controllerapi.BuildOptions, invokeConfig *controllerapi.InvokeConfig, c control.BuildxController, stdin io.ReadCloser, stdout io.WriteCloser, stderr console.File, progress *progress.Printer) (*MonitorBuildResult, error) {
defer func() { defer func() {
if err := c.Disconnect(ctx, curRef); err != nil { if err := c.Disconnect(ctx, curRef); err != nil {
logrus.Warnf("disconnect error: %v", err) logrus.Warnf("disconnect error: %v", err)
@@ -243,8 +244,8 @@ type monitor struct {
lastBuildResult *MonitorBuildResult lastBuildResult *MonitorBuildResult
} }
func (m *monitor) Build(ctx context.Context, options controllerapi.BuildOptions, in io.ReadCloser, progress progress.Writer) (ref string, resp *client.SolveResponse, err error) { func (m *monitor) Build(ctx context.Context, options *controllerapi.BuildOptions, in io.ReadCloser, progress progress.Writer) (ref string, resp *client.SolveResponse, input *build.Inputs, err error) {
ref, resp, err = m.BuildxController.Build(ctx, options, in, progress) ref, resp, _, err = m.BuildxController.Build(ctx, options, in, progress)
m.lastBuildResult = &MonitorBuildResult{Resp: resp, Err: err} // Record build result m.lastBuildResult = &MonitorBuildResult{Resp: resp, Err: err} // Record build result
return return
} }
@@ -261,19 +262,19 @@ func (m *monitor) AttachedSessionID() string {
return m.ref.Load().(string) return m.ref.Load().(string)
} }
func (m *monitor) Rollback(ctx context.Context, cfg controllerapi.InvokeConfig) string { func (m *monitor) Rollback(ctx context.Context, cfg *controllerapi.InvokeConfig) string {
pid := identity.NewID() pid := identity.NewID()
cfg1 := cfg cfg1 := cfg
cfg1.Rollback = true cfg1.Rollback = true
return m.startInvoke(ctx, pid, cfg1) return m.startInvoke(ctx, pid, cfg1)
} }
func (m *monitor) Exec(ctx context.Context, cfg controllerapi.InvokeConfig) string { func (m *monitor) Exec(ctx context.Context, cfg *controllerapi.InvokeConfig) string {
return m.startInvoke(ctx, identity.NewID(), cfg) return m.startInvoke(ctx, identity.NewID(), cfg)
} }
func (m *monitor) Attach(ctx context.Context, pid string) { func (m *monitor) Attach(ctx context.Context, pid string) {
m.startInvoke(ctx, pid, controllerapi.InvokeConfig{}) m.startInvoke(ctx, pid, &controllerapi.InvokeConfig{})
} }
func (m *monitor) Detach() { func (m *monitor) Detach() {
@@ -290,7 +291,7 @@ func (m *monitor) close() {
m.Detach() m.Detach()
} }
func (m *monitor) startInvoke(ctx context.Context, pid string, cfg controllerapi.InvokeConfig) string { func (m *monitor) startInvoke(ctx context.Context, pid string, cfg *controllerapi.InvokeConfig) string {
if m.invokeCancel != nil { if m.invokeCancel != nil {
m.invokeCancel() // Finish existing attach m.invokeCancel() // Finish existing attach
} }
@@ -316,7 +317,7 @@ func (m *monitor) startInvoke(ctx context.Context, pid string, cfg controllerapi
return pid return pid
} }
func (m *monitor) invoke(ctx context.Context, pid string, cfg controllerapi.InvokeConfig) error { func (m *monitor) invoke(ctx context.Context, pid string, cfg *controllerapi.InvokeConfig) error {
m.muxIO.Enable(1) m.muxIO.Enable(1)
defer m.muxIO.Disable(1) defer m.muxIO.Disable(1)
if err := m.muxIO.SwitchTo(1); err != nil { if err := m.muxIO.SwitchTo(1); err != nil {

View File

@@ -12,10 +12,10 @@ type Monitor interface {
control.BuildxController control.BuildxController
// Rollback re-runs the interactive container with initial rootfs contents. // Rollback re-runs the interactive container with initial rootfs contents.
Rollback(ctx context.Context, cfg controllerapi.InvokeConfig) string Rollback(ctx context.Context, cfg *controllerapi.InvokeConfig) string
// Rollback executes a process in the interactive container. // Rollback executes a process in the interactive container.
Exec(ctx context.Context, cfg controllerapi.InvokeConfig) string Exec(ctx context.Context, cfg *controllerapi.InvokeConfig) string
// Attach attaches IO to a process in the container. // Attach attaches IO to a process in the container.
Attach(ctx context.Context, pid string) Attach(ctx context.Context, pid string)
@@ -50,7 +50,6 @@ type CommandInfo struct {
// Command represents a command for debugging. // Command represents a command for debugging.
type Command interface { type Command interface {
// Exec executes the command. // Exec executes the command.
Exec(ctx context.Context, args []string) error Exec(ctx context.Context, args []string) error

View File

@@ -8,7 +8,7 @@ import (
"time" "time"
"github.com/docker/buildx/localstate" "github.com/docker/buildx/localstate"
"github.com/docker/docker/pkg/ioutils" "github.com/docker/buildx/util/confutil"
"github.com/gofrs/flock" "github.com/gofrs/flock"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -20,25 +20,25 @@ const (
activityDir = "activity" activityDir = "activity"
) )
func New(root string) (*Store, error) { func New(cfg *confutil.Config) (*Store, error) {
if err := os.MkdirAll(filepath.Join(root, instanceDir), 0700); err != nil { if err := cfg.MkdirAll(instanceDir, 0700); err != nil {
return nil, err return nil, err
} }
if err := os.MkdirAll(filepath.Join(root, defaultsDir), 0700); err != nil { if err := cfg.MkdirAll(defaultsDir, 0700); err != nil {
return nil, err return nil, err
} }
if err := os.MkdirAll(filepath.Join(root, activityDir), 0700); err != nil { if err := cfg.MkdirAll(activityDir, 0700); err != nil {
return nil, err return nil, err
} }
return &Store{root: root}, nil return &Store{cfg: cfg}, nil
} }
type Store struct { type Store struct {
root string cfg *confutil.Config
} }
func (s *Store) Txn() (*Txn, func(), error) { func (s *Store) Txn() (*Txn, func(), error) {
l := flock.New(filepath.Join(s.root, ".lock")) l := flock.New(filepath.Join(s.cfg.Dir(), ".lock"))
if err := l.Lock(); err != nil { if err := l.Lock(); err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -54,7 +54,7 @@ type Txn struct {
} }
func (t *Txn) List() ([]*NodeGroup, error) { func (t *Txn) List() ([]*NodeGroup, error) {
pp := filepath.Join(t.s.root, instanceDir) pp := filepath.Join(t.s.cfg.Dir(), instanceDir)
fis, err := os.ReadDir(pp) fis, err := os.ReadDir(pp)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -84,7 +84,7 @@ func (t *Txn) NodeGroupByName(name string) (*NodeGroup, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
dt, err := os.ReadFile(filepath.Join(t.s.root, instanceDir, name)) dt, err := os.ReadFile(filepath.Join(t.s.cfg.Dir(), instanceDir, name))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -110,7 +110,7 @@ func (t *Txn) Save(ng *NodeGroup) error {
if err != nil { if err != nil {
return err return err
} }
return ioutils.AtomicWriteFile(filepath.Join(t.s.root, instanceDir, name), dt, 0600) return t.s.cfg.AtomicWriteFile(filepath.Join(instanceDir, name), dt, 0600)
} }
func (t *Txn) Remove(name string) error { func (t *Txn) Remove(name string) error {
@@ -121,14 +121,14 @@ func (t *Txn) Remove(name string) error {
if err := t.RemoveLastActivity(name); err != nil { if err := t.RemoveLastActivity(name); err != nil {
return err return err
} }
ls, err := localstate.New(t.s.root) ls, err := localstate.New(t.s.cfg)
if err != nil { if err != nil {
return err return err
} }
if err := ls.RemoveBuilder(name); err != nil { if err := ls.RemoveBuilder(name); err != nil {
return err return err
} }
return os.RemoveAll(filepath.Join(t.s.root, instanceDir, name)) return os.RemoveAll(filepath.Join(t.s.cfg.Dir(), instanceDir, name))
} }
func (t *Txn) SetCurrent(key, name string, global, def bool) error { func (t *Txn) SetCurrent(key, name string, global, def bool) error {
@@ -141,28 +141,28 @@ func (t *Txn) SetCurrent(key, name string, global, def bool) error {
if err != nil { if err != nil {
return err return err
} }
if err := ioutils.AtomicWriteFile(filepath.Join(t.s.root, "current"), dt, 0600); err != nil { if err := t.s.cfg.AtomicWriteFile("current", dt, 0600); err != nil {
return err return err
} }
h := toHash(key) h := toHash(key)
if def { if def {
if err := ioutils.AtomicWriteFile(filepath.Join(t.s.root, defaultsDir, h), []byte(name), 0600); err != nil { if err := t.s.cfg.AtomicWriteFile(filepath.Join(defaultsDir, h), []byte(name), 0600); err != nil {
return err return err
} }
} else { } else {
os.RemoveAll(filepath.Join(t.s.root, defaultsDir, h)) // ignore error os.RemoveAll(filepath.Join(t.s.cfg.Dir(), defaultsDir, h)) // ignore error
} }
return nil return nil
} }
func (t *Txn) UpdateLastActivity(ng *NodeGroup) error { func (t *Txn) UpdateLastActivity(ng *NodeGroup) error {
return ioutils.AtomicWriteFile(filepath.Join(t.s.root, activityDir, ng.Name), []byte(time.Now().UTC().Format(time.RFC3339)), 0600) return t.s.cfg.AtomicWriteFile(filepath.Join(activityDir, ng.Name), []byte(time.Now().UTC().Format(time.RFC3339)), 0600)
} }
func (t *Txn) GetLastActivity(ng *NodeGroup) (la time.Time, _ error) { func (t *Txn) GetLastActivity(ng *NodeGroup) (la time.Time, _ error) {
dt, err := os.ReadFile(filepath.Join(t.s.root, activityDir, ng.Name)) dt, err := os.ReadFile(filepath.Join(t.s.cfg.Dir(), activityDir, ng.Name))
if err != nil { if err != nil {
if os.IsNotExist(errors.Cause(err)) { if os.IsNotExist(errors.Cause(err)) {
return la, nil return la, nil
@@ -177,7 +177,7 @@ func (t *Txn) RemoveLastActivity(name string) error {
if err != nil { if err != nil {
return err return err
} }
return os.RemoveAll(filepath.Join(t.s.root, activityDir, name)) return os.RemoveAll(filepath.Join(t.s.cfg.Dir(), activityDir, name))
} }
func (t *Txn) reset(key string) error { func (t *Txn) reset(key string) error {
@@ -185,11 +185,11 @@ func (t *Txn) reset(key string) error {
if err != nil { if err != nil {
return err return err
} }
return ioutils.AtomicWriteFile(filepath.Join(t.s.root, "current"), dt, 0600) return t.s.cfg.AtomicWriteFile("current", dt, 0600)
} }
func (t *Txn) Current(key string) (*NodeGroup, error) { func (t *Txn) Current(key string) (*NodeGroup, error) {
dt, err := os.ReadFile(filepath.Join(t.s.root, "current")) dt, err := os.ReadFile(filepath.Join(t.s.cfg.Dir(), "current"))
if err != nil { if err != nil {
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
return nil, err return nil, err
@@ -220,7 +220,7 @@ func (t *Txn) Current(key string) (*NodeGroup, error) {
h := toHash(key) h := toHash(key)
dt, err = os.ReadFile(filepath.Join(t.s.root, defaultsDir, h)) dt, err = os.ReadFile(filepath.Join(t.s.cfg.Dir(), defaultsDir, h))
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
t.reset(key) t.reset(key)

View File

@@ -5,6 +5,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/docker/buildx/util/confutil"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -15,7 +16,7 @@ func TestEmptyStartup(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
s, err := New(tmpdir) s, err := New(confutil.NewConfig(nil, confutil.WithDir(tmpdir)))
require.NoError(t, err) require.NoError(t, err)
txn, release, err := s.Txn() txn, release, err := s.Txn()
@@ -33,7 +34,7 @@ func TestNodeLocking(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
s, err := New(tmpdir) s, err := New(confutil.NewConfig(nil, confutil.WithDir(tmpdir)))
require.NoError(t, err) require.NoError(t, err)
_, release, err := s.Txn() _, release, err := s.Txn()
@@ -68,7 +69,7 @@ func TestNodeManagement(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
s, err := New(tmpdir) s, err := New(confutil.NewConfig(nil, confutil.WithDir(tmpdir)))
require.NoError(t, err) require.NoError(t, err)
txn, release, err := s.Txn() txn, release, err := s.Txn()
@@ -240,7 +241,7 @@ func TestNodeInvalidName(t *testing.T) {
t.Parallel() t.Parallel()
tmpdir := t.TempDir() tmpdir := t.TempDir()
s, err := New(tmpdir) s, err := New(confutil.NewConfig(nil, confutil.WithDir(tmpdir)))
require.NoError(t, err) require.NoError(t, err)
txn, release, err := s.Txn() txn, release, err := s.Txn()

View File

@@ -17,7 +17,7 @@ import (
// GetStore returns current builder instance store // GetStore returns current builder instance store
func GetStore(dockerCli command.Cli) (*store.Txn, func(), error) { func GetStore(dockerCli command.Cli) (*store.Txn, func(), error) {
s, err := store.New(confutil.ConfigDir(dockerCli)) s, err := store.New(confutil.NewConfig(dockerCli))
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@@ -103,6 +103,26 @@ target "build" {
require.Equal(t, ".", *def.Target["build"].Context) require.Equal(t, ".", *def.Target["build"].Context)
require.Equal(t, "Dockerfile", *def.Target["build"].Dockerfile) require.Equal(t, "Dockerfile", *def.Target["build"].Dockerfile)
require.Equal(t, map[string]*string{"HELLO": ptrstr("foo")}, def.Target["build"].Args) require.Equal(t, map[string]*string{"HELLO": ptrstr("foo")}, def.Target["build"].Args)
require.Equal(t, `{
"group": {
"default": {
"targets": [
"build"
]
}
},
"target": {
"build": {
"context": ".",
"dockerfile": "Dockerfile",
"args": {
"HELLO": "foo"
}
}
}
}
`, stdout.String())
} }
func testBakeLocal(t *testing.T, sb integration.Sandbox) { func testBakeLocal(t *testing.T, sb integration.Sandbox) {
@@ -1398,4 +1418,48 @@ target "second" {
require.Contains(t, stdout.String(), "Check complete, 1 warning has been found!") require.Contains(t, stdout.String(), "Check complete, 1 warning has been found!")
require.Contains(t, stdout.String(), "Check complete, 2 warnings have been found!") require.Contains(t, stdout.String(), "Check complete, 2 warnings have been found!")
}) })
t.Run("check for Dockerfile path printed with context when displaying rule check warnings with multiple build targets", func(t *testing.T) {
dockerfile := []byte(`
FROM busybox
copy Dockerfile .
`)
bakefile := []byte(`
target "first" {
dockerfile = "Dockerfile"
}
target "second" {
dockerfile = "subdir/Dockerfile"
}
target "third" {
dockerfile = "subdir/subsubdir/Dockerfile"
}
`)
dir := tmpdir(
t,
fstest.CreateDir("subdir", 0700),
fstest.CreateDir("subdir/subsubdir", 0700),
fstest.CreateFile("Dockerfile", dockerfile, 0600),
fstest.CreateFile("subdir/Dockerfile", dockerfile, 0600),
fstest.CreateFile("subdir/subsubdir/Dockerfile", dockerfile, 0600),
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
)
dockerfilePathFirst := filepath.Join("Dockerfile")
dockerfilePathSecond := filepath.Join("subdir", "Dockerfile")
dockerfilePathThird := filepath.Join("subdir", "subsubdir", "Dockerfile")
cmd := buildxCmd(
sb,
withDir(dir),
withArgs("bake", "--call", "check", "first", "second", "third"),
)
stdout := bytes.Buffer{}
stderr := bytes.Buffer{}
cmd.Stdout = &stdout
cmd.Stderr = &stderr
require.Error(t, cmd.Run(), stdout.String(), stderr.String())
require.Contains(t, stdout.String(), dockerfilePathFirst+":3")
require.Contains(t, stdout.String(), dockerfilePathSecond+":3")
require.Contains(t, stdout.String(), dockerfilePathThird+":3")
})
} }

View File

@@ -17,6 +17,7 @@ import (
"github.com/containerd/platforms" "github.com/containerd/platforms"
"github.com/creack/pty" "github.com/creack/pty"
"github.com/docker/buildx/localstate" "github.com/docker/buildx/localstate"
"github.com/docker/buildx/util/confutil"
"github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/gitutil"
"github.com/moby/buildkit/client" "github.com/moby/buildkit/client"
"github.com/moby/buildkit/frontend/subrequests/lint" "github.com/moby/buildkit/frontend/subrequests/lint"
@@ -167,7 +168,7 @@ COPY --from=base /etc/bar /bar
err = json.Unmarshal(dt, &md) err = json.Unmarshal(dt, &md)
require.NoError(t, err) require.NoError(t, err)
ls, err := localstate.New(buildxConfig(sb)) ls, err := localstate.New(confutil.NewConfig(nil, confutil.WithDir(buildxConfig(sb))))
require.NoError(t, err) require.NoError(t, err)
refParts := strings.Split(md.BuildRef, "/") refParts := strings.Split(md.BuildRef, "/")
@@ -209,7 +210,7 @@ COPY --from=base /etc/bar /bar
err = json.Unmarshal(dt, &md) err = json.Unmarshal(dt, &md)
require.NoError(t, err) require.NoError(t, err)
ls, err := localstate.New(buildxConfig(sb)) ls, err := localstate.New(confutil.NewConfig(nil, confutil.WithDir(buildxConfig(sb))))
require.NoError(t, err) require.NoError(t, err)
refParts := strings.Split(md.BuildRef, "/") refParts := strings.Split(md.BuildRef, "/")
@@ -261,7 +262,7 @@ COPY foo /foo
err = json.Unmarshal(dt, &md) err = json.Unmarshal(dt, &md)
require.NoError(t, err) require.NoError(t, err)
ls, err := localstate.New(buildxConfig(sb)) ls, err := localstate.New(confutil.NewConfig(nil, confutil.WithDir(buildxConfig(sb))))
require.NoError(t, err) require.NoError(t, err)
refParts := strings.Split(md.BuildRef, "/") refParts := strings.Split(md.BuildRef, "/")
@@ -492,11 +493,6 @@ RUN echo foo > /bar`)
require.NoError(t, err, string(out)) require.NoError(t, err, string(out))
require.True(t, buildDetailsPattern.MatchString(string(out)), fmt.Sprintf("expected build details link in output, got %q", out)) require.True(t, buildDetailsPattern.MatchString(string(out)), fmt.Sprintf("expected build details link in output, got %q", out))
if isExperimental() {
// FIXME: https://github.com/docker/buildx/issues/2382
t.Skip("build details link not displayed in experimental mode when build fails: https://github.com/docker/buildx/issues/2382")
}
// build erroneous dockerfile // build erroneous dockerfile
dockerfile = []byte(`FROM busybox:latest dockerfile = []byte(`FROM busybox:latest
RUN exit 1`) RUN exit 1`)
@@ -1291,6 +1287,29 @@ cOpy Dockerfile .
require.Error(t, cmd.Run(), stdout.String(), stderr.String()) require.Error(t, cmd.Run(), stdout.String(), stderr.String())
require.Contains(t, stdout.String(), "Check complete, 2 warnings have been found!") require.Contains(t, stdout.String(), "Check complete, 2 warnings have been found!")
}) })
t.Run("check for Dockerfile path printed with context when displaying rule check warnings", func(t *testing.T) {
dockerfile := []byte(`
frOM busybox as base
cOpy Dockerfile .
`)
dir := tmpdir(
t,
fstest.CreateDir("subdir", 0700),
fstest.CreateFile("subdir/Dockerfile", dockerfile, 0600),
)
dockerfilePath := filepath.Join(dir, "subdir", "Dockerfile")
cmd := buildxCmd(sb, withArgs("build", "--call=check", "-f", dockerfilePath, dir))
stdout := bytes.Buffer{}
stderr := bytes.Buffer{}
cmd.Stdout = &stdout
cmd.Stderr = &stderr
require.Error(t, cmd.Run(), stdout.String(), stderr.String())
require.Contains(t, stdout.String(), "Check complete, 2 warnings have been found!")
require.Contains(t, stdout.String(), dockerfilePath+":2")
require.Contains(t, stdout.String(), dockerfilePath+":3")
})
} }
func createTestProject(t *testing.T) string { func createTestProject(t *testing.T) string {

29
tests/common.go Normal file
View File

@@ -0,0 +1,29 @@
package tests
import (
"testing"
"github.com/moby/buildkit/util/testutil/integration"
"github.com/stretchr/testify/require"
)
var commonTests = []func(t *testing.T, sb integration.Sandbox){
testUnknownCommand,
testUnknownFlag,
}
func testUnknownCommand(t *testing.T, sb integration.Sandbox) {
cmd := buildxCmd(sb, withArgs("foo"))
out, err := cmd.CombinedOutput()
require.Error(t, err, string(out))
cmd = buildxCmd(sb, withArgs("imagetools", "foo"))
out, err = cmd.CombinedOutput()
require.Error(t, err, string(out))
}
func testUnknownFlag(t *testing.T, sb integration.Sandbox) {
cmd := buildxCmd(sb, withArgs("build", "--foo=bar"))
out, err := cmd.CombinedOutput()
require.Error(t, err, string(out))
}

View File

@@ -1,6 +1,9 @@
package tests package tests
import ( import (
"os"
"path"
"regexp"
"strings" "strings"
"testing" "testing"
@@ -19,6 +22,7 @@ var inspectTests = []func(t *testing.T, sb integration.Sandbox){
testInspect, testInspect,
testInspectBuildkitdFlags, testInspectBuildkitdFlags,
testInspectNetworkHostEntitlement, testInspectNetworkHostEntitlement,
testInspectBuildkitdConf,
} }
func testInspect(t *testing.T, sb integration.Sandbox) { func testInspect(t *testing.T, sb integration.Sandbox) {
@@ -109,3 +113,68 @@ func testInspectNetworkHostEntitlement(t *testing.T, sb integration.Sandbox) {
} }
require.Fail(t, "network.host insecure entitlement not found in inspect output") require.Fail(t, "network.host insecure entitlement not found in inspect output")
} }
func testInspectBuildkitdConf(t *testing.T, sb integration.Sandbox) {
if !isDockerContainerWorker(sb) {
t.Skip("only testing with docker-container worker")
}
buildkitdConf := `
# debug enables additional debug logging
debug = true
# insecure-entitlements allows insecure entitlements, disabled by default.
insecure-entitlements = [ "network.host", "security.insecure" ]
[log]
# log formatter: json or text
format = "text"
`
expectedContent := `debug = true
insecure-entitlements = ["network.host", "security.insecure"]
[log]
format = "text"
`
var builderName string
t.Cleanup(func() {
if builderName == "" {
return
}
out, err := rmCmd(sb, withArgs(builderName))
require.NoError(t, err, out)
})
dirConf := t.TempDir()
buildkitdConfPath := path.Join(dirConf, "buildkitd-conf.toml")
require.NoError(t, os.WriteFile(buildkitdConfPath, []byte(buildkitdConf), 0644))
out, err := createCmd(sb, withArgs("--driver", "docker-container", "--buildkitd-config="+buildkitdConfPath))
require.NoError(t, err, out)
builderName = strings.TrimSpace(out)
out, err = inspectCmd(sb, withArgs(builderName))
require.NoError(t, err, out)
var fileLines []string
var fileFound bool
var reConfLine = regexp.MustCompile(`^[\s\t]*>\s(.*)`)
for _, line := range strings.Split(out, "\n") {
if strings.HasPrefix(line, "File#buildkitd.toml:") {
fileFound = true
continue
}
if fileFound {
if matches := reConfLine.FindStringSubmatch(line); len(matches) > 1 {
fileLines = append(fileLines, matches[1])
} else {
break
}
}
}
if !fileFound {
require.Fail(t, "File#buildkitd.toml not found in inspect output")
}
require.Equal(t, expectedContent, strings.Join(fileLines, "\n"), "File#buildkitd.toml content mismatch")
}

View File

@@ -21,6 +21,7 @@ func init() {
func TestIntegration(t *testing.T) { func TestIntegration(t *testing.T) {
var tests []func(t *testing.T, sb integration.Sandbox) var tests []func(t *testing.T, sb integration.Sandbox)
tests = append(tests, commonTests...)
tests = append(tests, buildTests...) tests = append(tests, buildTests...)
tests = append(tests, bakeTests...) tests = append(tests, bakeTests...)
tests = append(tests, inspectTests...) tests = append(tests, inspectTests...)

View File

@@ -73,6 +73,11 @@ func (w *containerWorker) New(ctx context.Context, cfg *integration.BackendConfi
cl := func() error { cl := func() error {
cmd := exec.Command("buildx", "rm", "-f", name) cmd := exec.Command("buildx", "rm", "-f", name)
cmd.Env = append(
os.Environ(),
"BUILDX_CONFIG=/tmp/buildx-"+name,
"DOCKER_CONTEXT="+w.docker.DockerAddress(),
)
return cmd.Run() return cmd.Run()
} }

View File

@@ -56,6 +56,7 @@ func (w remoteWorker) New(ctx context.Context, cfg *integration.BackendConfig) (
cl = func() error { cl = func() error {
err := bkclose() err := bkclose()
cmd := exec.Command("buildx", "rm", "-f", name) cmd := exec.Command("buildx", "rm", "-f", name)
cmd.Env = append(os.Environ(), "BUILDX_CONFIG=/tmp/buildx-"+name)
if err1 := cmd.Run(); err == nil { if err1 := cmd.Run(); err == nil {
err = err1 err = err1
} }

View File

@@ -9,8 +9,7 @@
package tools package tools
import ( import (
_ "github.com/gogo/protobuf/protoc-gen-gogo" _ "github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto"
_ "github.com/gogo/protobuf/protoc-gen-gogofaster" _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
_ "github.com/gogo/protobuf/protoc-gen-gogoslick" _ "google.golang.org/protobuf/cmd/protoc-gen-go"
_ "github.com/golang/protobuf/protoc-gen-go"
) )

View File

@@ -1,41 +1,146 @@
package confutil package confutil
import ( import (
"crypto/rand"
"encoding/hex"
"os" "os"
"path"
"path/filepath" "path/filepath"
"sync"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/docker/pkg/ioutils"
"github.com/pelletier/go-toml" "github.com/pelletier/go-toml"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" fs "github.com/tonistiigi/fsutil/copy"
) )
// ConfigDir will look for correct configuration store path; const defaultBuildKitConfigFile = "buildkitd.default.toml"
// if `$BUILDX_CONFIG` is set - use it, otherwise use parent directory
// of Docker config file (i.e. `${DOCKER_CONFIG}/buildx`)
func ConfigDir(dockerCli command.Cli) string {
if buildxConfig := os.Getenv("BUILDX_CONFIG"); buildxConfig != "" {
logrus.Debugf("using config store %q based in \"$BUILDX_CONFIG\" environment variable", buildxConfig)
return buildxConfig
}
buildxConfig := filepath.Join(filepath.Dir(dockerCli.ConfigFile().Filename), "buildx") type Config struct {
logrus.Debugf("using default config store %q", buildxConfig) dir string
return buildxConfig chowner *chowner
} }
// DefaultConfigFile returns the default BuildKit configuration file path type chowner struct {
func DefaultConfigFile(dockerCli command.Cli) (string, bool) { uid int
f := path.Join(ConfigDir(dockerCli), "buildkitd.default.toml") gid int
}
type ConfigOption func(*configOptions)
type configOptions struct {
dir string
}
func WithDir(dir string) ConfigOption {
return func(o *configOptions) {
o.dir = dir
}
}
func NewConfig(dockerCli command.Cli, opts ...ConfigOption) *Config {
co := configOptions{}
for _, opt := range opts {
opt(&co)
}
configDir := co.dir
if configDir == "" {
configDir = os.Getenv("BUILDX_CONFIG")
if configDir == "" {
configDir = filepath.Join(filepath.Dir(dockerCli.ConfigFile().Filename), "buildx")
}
}
return &Config{
dir: configDir,
chowner: sudoer(configDir),
}
}
// Dir will look for correct configuration store path;
// if `$BUILDX_CONFIG` is set - use it, otherwise use parent directory
// of Docker config file (i.e. `${DOCKER_CONFIG}/buildx`)
func (c *Config) Dir() string {
return c.dir
}
// BuildKitConfigFile returns the default BuildKit configuration file path
func (c *Config) BuildKitConfigFile() (string, bool) {
f := filepath.Join(c.dir, defaultBuildKitConfigFile)
if _, err := os.Stat(f); err == nil { if _, err := os.Stat(f); err == nil {
return f, true return f, true
} }
return "", false return "", false
} }
// loadConfigTree loads BuildKit config toml tree // MkdirAll creates a directory and all necessary parents within the config dir.
func loadConfigTree(fp string) (*toml.Tree, error) { func (c *Config) MkdirAll(dir string, perm os.FileMode) error {
var chown fs.Chowner
if c.chowner != nil {
chown = func(user *fs.User) (*fs.User, error) {
return &fs.User{UID: c.chowner.uid, GID: c.chowner.gid}, nil
}
}
d := filepath.Join(c.dir, dir)
st, err := os.Stat(d)
if err != nil {
if os.IsNotExist(err) {
_, err := fs.MkdirAll(d, perm, chown, nil)
return err
}
return err
}
// if directory already exists, fix the owner if necessary
if c.chowner == nil {
return nil
}
currentOwner := fileOwner(st)
if currentOwner != nil && (currentOwner.uid != c.chowner.uid || currentOwner.gid != c.chowner.gid) {
return os.Chown(d, c.chowner.uid, c.chowner.gid)
}
return nil
}
// AtomicWriteFile writes data to a file within the config dir atomically
func (c *Config) AtomicWriteFile(filename string, data []byte, perm os.FileMode) error {
f := filepath.Join(c.dir, filename)
if err := ioutils.AtomicWriteFile(f, data, perm); err != nil {
return err
}
if c.chowner == nil {
return nil
}
return os.Chown(f, c.chowner.uid, c.chowner.gid)
}
var nodeIdentifierMu sync.Mutex
func (c *Config) TryNodeIdentifier() (out string) {
nodeIdentifierMu.Lock()
defer nodeIdentifierMu.Unlock()
sessionFilename := ".buildNodeID"
sessionFilepath := filepath.Join(c.Dir(), sessionFilename)
if _, err := os.Lstat(sessionFilepath); err != nil {
if os.IsNotExist(err) { // create a new file with stored randomness
b := make([]byte, 8)
if _, err := rand.Read(b); err != nil {
return out
}
if err := c.AtomicWriteFile(sessionFilename, []byte(hex.EncodeToString(b)), 0600); err != nil {
return out
}
}
}
dt, err := os.ReadFile(sessionFilepath)
if err == nil {
return string(dt)
}
return
}
// LoadConfigTree loads BuildKit config toml tree
func LoadConfigTree(fp string) (*toml.Tree, error) {
f, err := os.Open(fp) f, err := os.Open(fp)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {

View File

@@ -0,0 +1,60 @@
//go:build !windows
// +build !windows
package confutil
import (
"os"
"os/user"
"path/filepath"
"strconv"
"strings"
"syscall"
)
// sudoer returns the user that invoked the current process with sudo only if
// sudo HOME env matches the home directory of the user that ran sudo and is
// part of configDir.
func sudoer(configDir string) *chowner {
if _, ok := os.LookupEnv("SUDO_COMMAND"); !ok {
return nil
}
suidenv := os.Getenv("SUDO_UID") // https://www.sudo.ws/docs/man/sudo.man/#SUDO_UID
sgidenv := os.Getenv("SUDO_GID") // https://www.sudo.ws/docs/man/sudo.man/#SUDO_GID
if suidenv == "" || sgidenv == "" {
return nil
}
u, err := user.LookupId(suidenv)
if err != nil {
return nil
}
suid, err := strconv.Atoi(suidenv)
if err != nil {
return nil
}
sgid, err := strconv.Atoi(sgidenv)
if err != nil {
return nil
}
home, _ := os.UserHomeDir()
if home == "" || u.HomeDir != home {
return nil
}
if ok, _ := isSubPath(home, configDir); !ok {
return nil
}
return &chowner{uid: suid, gid: sgid}
}
func fileOwner(fi os.FileInfo) *chowner {
st := fi.Sys().(*syscall.Stat_t)
return &chowner{uid: int(st.Uid), gid: int(st.Gid)}
}
func isSubPath(basePath, subPath string) (bool, error) {
rel, err := filepath.Rel(basePath, subPath)
if err != nil {
return false, err
}
return !strings.HasPrefix(rel, "..") && rel != ".", nil
}

View File

@@ -0,0 +1,58 @@
//go:build !windows
// +build !windows
package confutil
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestIsSubPath(t *testing.T) {
tests := []struct {
name string
basePath string
subPath string
expected bool
}{
{
name: "SubPath is a direct subdirectory",
basePath: "/home/user",
subPath: "/home/user/docs",
expected: true,
},
{
name: "SubPath is the same as basePath",
basePath: "/home/user",
subPath: "/home/user",
expected: false,
},
{
name: "SubPath is not a subdirectory",
basePath: "/home/user",
subPath: "/home/otheruser",
expected: false,
},
{
name: "SubPath is a nested subdirectory",
basePath: "/home/user",
subPath: "/home/user/docs/reports",
expected: true,
},
{
name: "SubPath is a sibling directory",
basePath: "/home/user",
subPath: "/home/user2",
expected: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
ok, err := isSubPath(tt.basePath, tt.subPath)
assert.NoError(t, err)
assert.Equal(t, tt.expected, ok)
})
}
}

View File

@@ -0,0 +1,11 @@
package confutil
import "os"
func sudoer(_ string) *chowner {
return nil
}
func fileOwner(_ os.FileInfo) *chowner {
return nil
}

View File

@@ -32,7 +32,7 @@ func LoadConfigFiles(bkconfig string) (map[string][]byte, error) {
} }
// Load config tree // Load config tree
btoml, err := loadConfigTree(bkconfig) btoml, err := LoadConfigTree(bkconfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -1,34 +0,0 @@
package confutil
import (
"crypto/rand"
"encoding/hex"
"os"
"path/filepath"
"sync"
)
var nodeIdentifierMu sync.Mutex
func TryNodeIdentifier(configDir string) (out string) {
nodeIdentifierMu.Lock()
defer nodeIdentifierMu.Unlock()
sessionFile := filepath.Join(configDir, ".buildNodeID")
if _, err := os.Lstat(sessionFile); err != nil {
if os.IsNotExist(err) { // create a new file with stored randomness
b := make([]byte, 8)
if _, err := rand.Read(b); err != nil {
return out
}
if err := os.WriteFile(sessionFile, []byte(hex.EncodeToString(b)), 0600); err != nil {
return out
}
}
}
dt, err := os.ReadFile(sessionFile)
if err == nil {
return string(dt)
}
return
}

View File

@@ -65,7 +65,6 @@ func hyperlink(url string) string {
type ErrorWithBuildRef struct { type ErrorWithBuildRef struct {
Ref string Ref string
Err error Err error
Msg string
} }
func (e *ErrorWithBuildRef) Error() string { func (e *ErrorWithBuildRef) Error() string {

View File

@@ -70,3 +70,5 @@ benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) - [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
- [FreeCache](https://github.com/coocood/freecache) - [FreeCache](https://github.com/coocood/freecache)
- [FastCache](https://github.com/VictoriaMetrics/fastcache) - [FastCache](https://github.com/VictoriaMetrics/fastcache)
- [Ristretto](https://github.com/dgraph-io/ristretto)
- [Badger](https://github.com/dgraph-io/badger)

View File

@@ -19,10 +19,13 @@ const (
// Store the primes in an array as well. // Store the primes in an array as well.
// //
// The consts are used when possible in Go code to avoid MOVs but we need a // The consts are used when possible in Go code to avoid MOVs but we need a
// contiguous array of the assembly code. // contiguous array for the assembly code.
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5} var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
// Digest implements hash.Hash64. // Digest implements hash.Hash64.
//
// Note that a zero-valued Digest is not ready to receive writes.
// Call Reset or create a Digest using New before calling other methods.
type Digest struct { type Digest struct {
v1 uint64 v1 uint64
v2 uint64 v2 uint64
@@ -33,19 +36,31 @@ type Digest struct {
n int // how much of mem is used n int // how much of mem is used
} }
// New creates a new Digest that computes the 64-bit xxHash algorithm. // New creates a new Digest with a zero seed.
func New() *Digest { func New() *Digest {
return NewWithSeed(0)
}
// NewWithSeed creates a new Digest with the given seed.
func NewWithSeed(seed uint64) *Digest {
var d Digest var d Digest
d.Reset() d.ResetWithSeed(seed)
return &d return &d
} }
// Reset clears the Digest's state so that it can be reused. // Reset clears the Digest's state so that it can be reused.
// It uses a seed value of zero.
func (d *Digest) Reset() { func (d *Digest) Reset() {
d.v1 = primes[0] + prime2 d.ResetWithSeed(0)
d.v2 = prime2 }
d.v3 = 0
d.v4 = -primes[0] // ResetWithSeed clears the Digest's state so that it can be reused.
// It uses the given seed to initialize the state.
func (d *Digest) ResetWithSeed(seed uint64) {
d.v1 = seed + prime1 + prime2
d.v2 = seed + prime2
d.v3 = seed
d.v4 = seed - prime1
d.total = 0 d.total = 0
d.n = 0 d.n = 0
} }

View File

@@ -6,7 +6,7 @@
package xxhash package xxhash
// Sum64 computes the 64-bit xxHash digest of b. // Sum64 computes the 64-bit xxHash digest of b with a zero seed.
// //
//go:noescape //go:noescape
func Sum64(b []byte) uint64 func Sum64(b []byte) uint64

View File

@@ -3,7 +3,7 @@
package xxhash package xxhash
// Sum64 computes the 64-bit xxHash digest of b. // Sum64 computes the 64-bit xxHash digest of b with a zero seed.
func Sum64(b []byte) uint64 { func Sum64(b []byte) uint64 {
// A simpler version would be // A simpler version would be
// d := New() // d := New()

View File

@@ -5,7 +5,7 @@
package xxhash package xxhash
// Sum64String computes the 64-bit xxHash digest of s. // Sum64String computes the 64-bit xxHash digest of s with a zero seed.
func Sum64String(s string) uint64 { func Sum64String(s string) uint64 {
return Sum64([]byte(s)) return Sum64([]byte(s))
} }

View File

@@ -33,7 +33,7 @@ import (
// //
// See https://github.com/golang/go/issues/42739 for discussion. // See https://github.com/golang/go/issues/42739 for discussion.
// Sum64String computes the 64-bit xxHash digest of s. // Sum64String computes the 64-bit xxHash digest of s with a zero seed.
// It may be faster than Sum64([]byte(s)) by avoiding a copy. // It may be faster than Sum64([]byte(s)) by avoiding a copy.
func Sum64String(s string) uint64 { func Sum64String(s string) uint64 {
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})) b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))

View File

@@ -403,7 +403,7 @@ func (o *ProjectOptions) GetWorkingDir() (string, error) {
return os.Getwd() return os.Getwd()
} }
func (o *ProjectOptions) GeConfigFiles() ([]types.ConfigFile, error) { func (o *ProjectOptions) GetConfigFiles() ([]types.ConfigFile, error) {
configPaths, err := o.getConfigPaths() configPaths, err := o.getConfigPaths()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -466,7 +466,7 @@ func (o *ProjectOptions) LoadModel(ctx context.Context) (map[string]any, error)
// prepare converts ProjectOptions into loader's types.ConfigDetails and configures default load options // prepare converts ProjectOptions into loader's types.ConfigDetails and configures default load options
func (o *ProjectOptions) prepare() (types.ConfigDetails, error) { func (o *ProjectOptions) prepare() (types.ConfigDetails, error) {
configs, err := o.GeConfigFiles() configs, err := o.GetConfigFiles()
if err != nil { if err != nil {
return types.ConfigDetails{}, err return types.ConfigDetails{}, err
} }

View File

@@ -119,7 +119,7 @@ loop:
offset = i + 1 offset = i + 1
inherited = rune == '\n' inherited = rune == '\n'
break loop break loop
case '_', '.', '-', '[', ']': case '_', '.', '[', ']':
default: default:
// variable name should match [A-Za-z0-9_.-] // variable name should match [A-Za-z0-9_.-]
if unicode.IsLetter(rune) || unicode.IsNumber(rune) { if unicode.IsLetter(rune) || unicode.IsNumber(rune) {

View File

@@ -79,7 +79,7 @@ func resolveSecretsEnvironment(dict map[string]any, environment types.Mapping) {
continue continue
} }
if found, ok := environment[env]; ok { if found, ok := environment[env]; ok {
secret["content"] = found secret[types.SecretConfigXValue] = found
} }
secrets[name] = secret secrets[name] = secret
} }

View File

@@ -163,8 +163,15 @@ func getExtendsBaseFromFile(
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
services := source["services"].(map[string]any) m, ok := source["services"]
_, ok := services[ref] if !ok {
return nil, nil, fmt.Errorf("cannot extend service %q in %s: no services section", name, local)
}
services, ok := m.(map[string]any)
if !ok {
return nil, nil, fmt.Errorf("cannot extend service %q in %s: services must be a mapping", name, local)
}
_, ok = services[ref]
if !ok { if !ok {
return nil, nil, fmt.Errorf( return nil, nil, fmt.Errorf(
"cannot extend service %q in %s: service %q not found in %s", "cannot extend service %q in %s: service %q not found in %s",

View File

@@ -118,7 +118,9 @@ services:
- "a 7:* rmw" - "a 7:* rmw"
devices: devices:
- "/dev/ttyUSB0:/dev/ttyUSB0" - source: /dev/ttyUSB0
target: /dev/ttyUSB0
permissions: rwm
# String or list # String or list
# dns: 8.8.8.8 # dns: 8.8.8.8

View File

@@ -738,7 +738,9 @@ func Transform(source interface{}, target interface{}) error {
DecodeHook: mapstructure.ComposeDecodeHookFunc( DecodeHook: mapstructure.ComposeDecodeHookFunc(
nameServices, nameServices,
decoderHook, decoderHook,
cast), cast,
secretConfigDecoderHook,
),
Result: target, Result: target,
TagName: "yaml", TagName: "yaml",
Metadata: &data, Metadata: &data,
@@ -764,6 +766,28 @@ func nameServices(from reflect.Value, to reflect.Value) (interface{}, error) {
return from.Interface(), nil return from.Interface(), nil
} }
func secretConfigDecoderHook(from, to reflect.Type, data interface{}) (interface{}, error) {
// Check if the input is a map and we're decoding into a SecretConfig
if from.Kind() == reflect.Map && to == reflect.TypeOf(types.SecretConfig{}) {
if v, ok := data.(map[string]interface{}); ok {
if ext, ok := v["#extensions"].(map[string]interface{}); ok {
if val, ok := ext[types.SecretConfigXValue].(string); ok {
// Return a map with the Content field populated
v["Content"] = val
delete(ext, types.SecretConfigXValue)
if len(ext) == 0 {
delete(v, "#extensions")
}
}
}
}
}
// Return the original data so the rest is handled by default mapstructure logic
return data, nil
}
// keys need to be converted to strings for jsonschema // keys need to be converted to strings for jsonschema
func convertToStringKeysRecursive(value interface{}, keyPrefix string) (interface{}, error) { func convertToStringKeysRecursive(value interface{}, keyPrefix string) (interface{}, error) {
if mapping, ok := value.(map[string]interface{}); ok { if mapping, ok := value.(map[string]interface{}); ok {

View File

@@ -36,7 +36,6 @@ func init() {
unique["services.*.annotations"] = keyValueIndexer unique["services.*.annotations"] = keyValueIndexer
unique["services.*.build.args"] = keyValueIndexer unique["services.*.build.args"] = keyValueIndexer
unique["services.*.build.additional_contexts"] = keyValueIndexer unique["services.*.build.additional_contexts"] = keyValueIndexer
unique["services.*.build.extra_hosts"] = keyValueIndexer
unique["services.*.build.platform"] = keyValueIndexer unique["services.*.build.platform"] = keyValueIndexer
unique["services.*.build.tags"] = keyValueIndexer unique["services.*.build.tags"] = keyValueIndexer
unique["services.*.build.labels"] = keyValueIndexer unique["services.*.build.labels"] = keyValueIndexer
@@ -51,7 +50,6 @@ func init() {
unique["services.*.environment"] = keyValueIndexer unique["services.*.environment"] = keyValueIndexer
unique["services.*.env_file"] = envFileIndexer unique["services.*.env_file"] = envFileIndexer
unique["services.*.expose"] = exposeIndexer unique["services.*.expose"] = exposeIndexer
unique["services.*.extra_hosts"] = keyValueIndexer
unique["services.*.labels"] = keyValueIndexer unique["services.*.labels"] = keyValueIndexer
unique["services.*.links"] = keyValueIndexer unique["services.*.links"] = keyValueIndexer
unique["services.*.networks.*.aliases"] = keyValueIndexer unique["services.*.networks.*.aliases"] = keyValueIndexer
@@ -62,6 +60,7 @@ func init() {
unique["services.*.sysctls"] = keyValueIndexer unique["services.*.sysctls"] = keyValueIndexer
unique["services.*.tmpfs"] = keyValueIndexer unique["services.*.tmpfs"] = keyValueIndexer
unique["services.*.volumes"] = volumeIndexer unique["services.*.volumes"] = volumeIndexer
unique["services.*.devices"] = deviceMappingIndexer
} }
// EnforceUnicity removes redefinition of elements declared in a sequence // EnforceUnicity removes redefinition of elements declared in a sequence
@@ -108,16 +107,16 @@ func enforceUnicity(value any, p tree.Path) (any, error) {
return value, nil return value, nil
} }
func keyValueIndexer(y any, p tree.Path) (string, error) { func keyValueIndexer(v any, p tree.Path) (string, error) {
switch value := y.(type) { switch value := v.(type) {
case string: case string:
key, _, found := strings.Cut(value, "=") key, _, found := strings.Cut(value, "=")
if !found { if found {
return value, nil return key, nil
} }
return key, nil return value, nil
default: default:
return "", fmt.Errorf("%s: unexpected type %T", p, y) return "", fmt.Errorf("%s: unexpected type %T", p, v)
} }
} }
@@ -139,6 +138,24 @@ func volumeIndexer(y any, p tree.Path) (string, error) {
return "", nil return "", nil
} }
func deviceMappingIndexer(y any, p tree.Path) (string, error) {
switch value := y.(type) {
case map[string]any:
target, ok := value["target"].(string)
if !ok {
return "", fmt.Errorf("service device %s is missing a mount target", p)
}
return target, nil
case string:
arr := strings.Split(value, ":")
if len(arr) == 1 {
return arr[0], nil
}
return arr[1], nil
}
return "", nil
}
func exposeIndexer(a any, path tree.Path) (string, error) { func exposeIndexer(a any, path tree.Path) (string, error) {
switch v := a.(type) { switch v := a.(type) {
case string: case string:

View File

@@ -19,7 +19,6 @@
"include": { "include": {
"type": "array", "type": "array",
"items": { "items": {
"type": "object",
"$ref": "#/definitions/include" "$ref": "#/definitions/include"
}, },
"description": "compose sub-projects to be included." "description": "compose sub-projects to be included."
@@ -115,7 +114,7 @@
"pull": {"type": ["boolean", "string"]}, "pull": {"type": ["boolean", "string"]},
"target": {"type": "string"}, "target": {"type": "string"},
"shm_size": {"type": ["integer", "string"]}, "shm_size": {"type": ["integer", "string"]},
"extra_hosts": {"$ref": "#/definitions/list_or_dict"}, "extra_hosts": {"$ref": "#/definitions/extra_hosts"},
"isolation": {"type": "string"}, "isolation": {"type": "string"},
"privileged": {"type": ["boolean", "string"]}, "privileged": {"type": ["boolean", "string"]},
"secrets": {"$ref": "#/definitions/service_config_or_secret"}, "secrets": {"$ref": "#/definitions/service_config_or_secret"},
@@ -216,7 +215,25 @@
] ]
}, },
"device_cgroup_rules": {"$ref": "#/definitions/list_of_strings"}, "device_cgroup_rules": {"$ref": "#/definitions/list_of_strings"},
"devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "devices": {
"type": "array",
"items": {
"oneOf": [
{"type": "string"},
{
"type": "object",
"required": ["source"],
"properties": {
"source": {"type": "string"},
"target": {"type": "string"},
"permissions": {"type": "string"}
},
"additionalProperties": false,
"patternProperties": {"^x-": {}}
}
]
}
},
"dns": {"$ref": "#/definitions/string_or_list"}, "dns": {"$ref": "#/definitions/string_or_list"},
"dns_opt": {"type": "array","items": {"type": "string"}, "uniqueItems": true}, "dns_opt": {"type": "array","items": {"type": "string"}, "uniqueItems": true},
"dns_search": {"$ref": "#/definitions/string_or_list"}, "dns_search": {"$ref": "#/definitions/string_or_list"},
@@ -249,7 +266,7 @@
] ]
}, },
"external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"extra_hosts": {"$ref": "#/definitions/list_or_dict"}, "extra_hosts": {"$ref": "#/definitions/extra_hosts"},
"group_add": { "group_add": {
"type": "array", "type": "array",
"items": { "items": {
@@ -854,6 +871,21 @@
] ]
}, },
"extra_hosts": {
"oneOf": [
{
"type": "object",
"patternProperties": {
".+": {
"type": ["string", "array"]
}
},
"additionalProperties": false
},
{"type": "array", "items": {"type": "string"}, "uniqueItems": true}
]
},
"blkio_limit": { "blkio_limit": {
"type": "object", "type": "object",
"properties": { "properties": {

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