mirror of
https://github.com/docker/compose.git
synced 2026-02-10 10:39:23 +08:00
Compare commits
261 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6007d4c7e7 | ||
|
|
69bcb962bf | ||
|
|
9b4fcce034 | ||
|
|
da5c57c29d | ||
|
|
e25265dd55 | ||
|
|
e19e1278b5 | ||
|
|
585c4db4f9 | ||
|
|
be8c7e6c60 | ||
|
|
27f59d7f42 | ||
|
|
2681ed17a7 | ||
|
|
ee75be342b | ||
|
|
157617480a | ||
|
|
88aae9c46e | ||
|
|
7755302348 | ||
|
|
147923c44c | ||
|
|
289faae5fa | ||
|
|
e7aa484b78 | ||
|
|
ae3309afab | ||
|
|
0b5fb36eb5 | ||
|
|
63920c4cc0 | ||
|
|
a03f2562df | ||
|
|
a07f2b8ded | ||
|
|
f45a3ebcfd | ||
|
|
7fec70b6c7 | ||
|
|
ce463d50b2 | ||
|
|
fa7e85ed83 | ||
|
|
d9423f6872 | ||
|
|
5add90240d | ||
|
|
07602f2070 | ||
|
|
cf7e31f731 | ||
|
|
fa08127456 | ||
|
|
4ee52ad168 | ||
|
|
4a4776ec57 | ||
|
|
713de5bb9e | ||
|
|
9ded1684cd | ||
|
|
8bc8593fd0 | ||
|
|
8978c1027d | ||
|
|
032e0309ee | ||
|
|
38ba35e165 | ||
|
|
56e0ba8080 | ||
|
|
9752fa5500 | ||
|
|
4761fd88b0 | ||
|
|
02c8e63545 | ||
|
|
ab7a6e9322 | ||
|
|
2ca7b96e33 | ||
|
|
a32dc3da72 | ||
|
|
db260938c1 | ||
|
|
5aea94794c | ||
|
|
d07c437ce8 | ||
|
|
da72230c39 | ||
|
|
a429c09dfa | ||
|
|
df3c27c864 | ||
|
|
956891af54 | ||
|
|
a473341058 | ||
|
|
385b3f5c96 | ||
|
|
2d482e61ce | ||
|
|
c75418ee07 | ||
|
|
0cdc5c9bff | ||
|
|
b768232c0e | ||
|
|
09689400e5 | ||
|
|
cb3691154b | ||
|
|
b387ba4a05 | ||
|
|
7cd569922e | ||
|
|
eec2bb7ea6 | ||
|
|
2c15aef2ed | ||
|
|
290366205b | ||
|
|
a91ca95a71 | ||
|
|
beb81a73f9 | ||
|
|
f217207876 | ||
|
|
02ffe2ac6c | ||
|
|
f48131fb66 | ||
|
|
4dd369bdcb | ||
|
|
ad73766bf2 | ||
|
|
3c1f5a1815 | ||
|
|
42d1e4c333 | ||
|
|
6ca8663bda | ||
|
|
b33ecf65e8 | ||
|
|
04b8ac5fe4 | ||
|
|
d09948da41 | ||
|
|
f1efbb8322 | ||
|
|
1d52012b82 | ||
|
|
1d69f4a68c | ||
|
|
6078b4d99d | ||
|
|
73e593e69a | ||
|
|
51499f645b | ||
|
|
5165b0f814 | ||
|
|
93dd1a4558 | ||
|
|
ba3f5664c0 | ||
|
|
c420bc44c4 | ||
|
|
60681a824c | ||
|
|
19ad737ee7 | ||
|
|
d3a260e533 | ||
|
|
e75329dce2 | ||
|
|
1dc0be2c30 | ||
|
|
3bac9ffd08 | ||
|
|
f266715dd0 | ||
|
|
c2cb0aef6b | ||
|
|
fbc62d111e | ||
|
|
0d40064ce8 | ||
|
|
91a6eafa1d | ||
|
|
f36ee00f71 | ||
|
|
29ede3ba7d | ||
|
|
bf6d7bf47e | ||
|
|
fc66da06db | ||
|
|
909211dd61 | ||
|
|
0dc9852c67 | ||
|
|
a478702236 | ||
|
|
2c12ad19db | ||
|
|
038ea8441a | ||
|
|
9e98e6101e | ||
|
|
52f04229c0 | ||
|
|
28895d0322 | ||
|
|
a926f7d717 | ||
|
|
fe046915eb | ||
|
|
adbd61e5d6 | ||
|
|
e37ac04329 | ||
|
|
cab2c2a44e | ||
|
|
1946de598d | ||
|
|
8e29a138aa | ||
|
|
3c8da0afee | ||
|
|
1b12c867c5 | ||
|
|
1a4fc55fd7 | ||
|
|
efc939dcee | ||
|
|
d6e9f79ba6 | ||
|
|
b4c44a431f | ||
|
|
fb5a8644c3 | ||
|
|
95660c5e5a | ||
|
|
f6ddd6ae88 | ||
|
|
4ae7066955 | ||
|
|
fd954f266c | ||
|
|
d62e21025c | ||
|
|
6a2d16bd10 | ||
|
|
4d47da6dc2 | ||
|
|
8f91793fb5 | ||
|
|
1d2223fb23 | ||
|
|
d4f6000712 | ||
|
|
c50d16cd78 | ||
|
|
3875e13fad | ||
|
|
c89f30170d | ||
|
|
41a9b91887 | ||
|
|
5fc2b2a71c | ||
|
|
b1cd40c316 | ||
|
|
362ab0733f | ||
|
|
f35d2cfb3b | ||
|
|
17ba6c7188 | ||
|
|
1c37f1abb6 | ||
|
|
485b6200ee | ||
|
|
8c17a35609 | ||
|
|
6b9667401a | ||
|
|
9a1e589ce8 | ||
|
|
5e147e852e | ||
|
|
29308cb97e | ||
|
|
0b0242d0ac | ||
|
|
5a704004d3 | ||
|
|
cb95910018 | ||
|
|
f42226e352 | ||
|
|
0cc3c7a550 | ||
|
|
f7ee9c8a0c | ||
|
|
35efa97b7d | ||
|
|
9e17a091be | ||
|
|
4bbc6c609f | ||
|
|
69f1430a49 | ||
|
|
7cf7c6414f | ||
|
|
0e0ed91a39 | ||
|
|
66524e7728 | ||
|
|
c626befee1 | ||
|
|
60ee6adcd2 | ||
|
|
8faf1eb808 | ||
|
|
3b0601b671 | ||
|
|
f42374bb18 | ||
|
|
b046a5ef72 | ||
|
|
1570c6c076 | ||
|
|
674e13fb6d | ||
|
|
6fa173124a | ||
|
|
2c69fc3d4d | ||
|
|
317ebcd3b0 | ||
|
|
5cf1f0e2a4 | ||
|
|
6198ed5bd2 | ||
|
|
00ccddbde8 | ||
|
|
63b441401e | ||
|
|
3a7982fe45 | ||
|
|
5430caa172 | ||
|
|
ee1b1e0a93 | ||
|
|
26e46d7cc8 | ||
|
|
a9e76943f6 | ||
|
|
b6a0df8d3c | ||
|
|
5a063b7510 | ||
|
|
ae49bba9be | ||
|
|
51acc58453 | ||
|
|
7c999d7f93 | ||
|
|
ad750d6143 | ||
|
|
fe382df507 | ||
|
|
6501d59efc | ||
|
|
33a782572f | ||
|
|
65803ea12e | ||
|
|
f613379373 | ||
|
|
3553aa26a6 | ||
|
|
257ea7b75d | ||
|
|
d219aa66f4 | ||
|
|
c9ebfad78e | ||
|
|
8e57362a0f | ||
|
|
29630f184e | ||
|
|
6514c680a5 | ||
|
|
3394bf031b | ||
|
|
832a08f579 | ||
|
|
aadce87b16 | ||
|
|
b3207c455d | ||
|
|
769b7391ba | ||
|
|
149b882ebf | ||
|
|
c97e40e2b8 | ||
|
|
22e23bd4dc | ||
|
|
2dde5faeb8 | ||
|
|
f7825a56bf | ||
|
|
4cf075ea0a | ||
|
|
4f491ffa98 | ||
|
|
ea1c26d22a | ||
|
|
9a5fa05ad6 | ||
|
|
276c229458 | ||
|
|
eef448dc64 | ||
|
|
343117233b | ||
|
|
f599a8cdd2 | ||
|
|
63b06f5563 | ||
|
|
1d34661e91 | ||
|
|
0f9e6ab832 | ||
|
|
15c9651a3a | ||
|
|
4893a8b9ad | ||
|
|
97530790fa | ||
|
|
213c03f99a | ||
|
|
ebd7b761f2 | ||
|
|
ea48480d80 | ||
|
|
8151b59288 | ||
|
|
ec49baca56 | ||
|
|
7b9ad96240 | ||
|
|
9b67a48c33 | ||
|
|
0d0e12cc85 | ||
|
|
92fafccfb2 | ||
|
|
fee8aee8f0 | ||
|
|
40f5786e68 | ||
|
|
61e44da936 | ||
|
|
0bf7d1ea25 | ||
|
|
80ace63dfb | ||
|
|
27e90a3fdf | ||
|
|
3ca75bdf55 | ||
|
|
eb3074bbda | ||
|
|
f4fc010d6b | ||
|
|
693b9ef078 | ||
|
|
046879a4a2 | ||
|
|
7c79b23005 | ||
|
|
ad4cbee498 | ||
|
|
60256a875c | ||
|
|
45bd60c33a | ||
|
|
cf89fd1aa1 | ||
|
|
23fef850b9 | ||
|
|
12b73bea73 | ||
|
|
2e71440bee | ||
|
|
d49a68ecbf | ||
|
|
be83f63f26 | ||
|
|
9a9227ce64 | ||
|
|
024f8ebdc5 | ||
|
|
8c622da20b | ||
|
|
bbb2b76a14 |
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -12,6 +12,12 @@ body:
|
||||
Include both the current behavior (what you are seeing) as well as what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
[Docker Swarm](https://www.mirantis.com/software/swarm/) uses a distinct compose file parser and
|
||||
as such doesn't support some of the recent features of Docker Compose. Please contact Mirantis
|
||||
if you need assistance with compose file support in Docker Swarm.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps To Reproduce
|
||||
|
||||
13
.github/workflows/ci.yml
vendored
13
.github/workflows/ci.yml
vendored
@@ -156,9 +156,8 @@ jobs:
|
||||
- plugin
|
||||
- standalone
|
||||
engine:
|
||||
- 26
|
||||
- 27
|
||||
- 28
|
||||
- 27 # old stable (latest major - 1)
|
||||
- 28 # current stable
|
||||
steps:
|
||||
- name: Prepare
|
||||
run: |
|
||||
@@ -183,6 +182,11 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up Docker Model
|
||||
run: |
|
||||
sudo apt-get install docker-model-plugin
|
||||
docker model version
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
@@ -190,6 +194,9 @@ jobs:
|
||||
check-latest: true
|
||||
cache: true
|
||||
|
||||
- name: Build example provider
|
||||
run: make example-provider
|
||||
|
||||
- name: Build
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
|
||||
@@ -30,6 +30,12 @@ linters:
|
||||
deny:
|
||||
- pkg: io/ioutil
|
||||
desc: io/ioutil package has been deprecated
|
||||
- pkg: github.com/docker/docker/errdefs
|
||||
desc: use github.com/containerd/errdefs instead.
|
||||
- pkg: golang.org/x/exp/maps
|
||||
desc: use stdlib maps package
|
||||
- pkg: golang.org/x/exp/slices
|
||||
desc: use stdlib slices package
|
||||
- pkg: gopkg.in/yaml.v2
|
||||
desc: compose-go uses yaml.v3
|
||||
gocritic:
|
||||
|
||||
@@ -4,12 +4,15 @@
|
||||
* Windows:
|
||||
* [Docker Desktop](https://docs.docker.com/desktop/setup/install/windows-install/)
|
||||
* make
|
||||
* go (see [go.mod](go.mod) for minimum version)
|
||||
* macOS:
|
||||
* [Docker Desktop](https://docs.docker.com/desktop/setup/install/mac-install/)
|
||||
* make
|
||||
* go (see [go.mod](go.mod) for minimum version)
|
||||
* Linux:
|
||||
* [Docker 20.10 or later](https://docs.docker.com/engine/install/)
|
||||
* make
|
||||
* go (see [go.mod](go.mod) for minimum version)
|
||||
|
||||
### Building the CLI
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ARG GO_VERSION=1.23.8
|
||||
ARG GO_VERSION=1.24.9
|
||||
ARG XX_VERSION=1.6.1
|
||||
ARG GOLANGCI_LINT_VERSION=v2.0.2
|
||||
ARG ADDLICENSE_VERSION=v1.0.0
|
||||
|
||||
124
MAINTAINERS
124
MAINTAINERS
@@ -1,124 +0,0 @@
|
||||
# Docker maintainers file
|
||||
#
|
||||
# This file describes who runs the docker/compose project and how.
|
||||
# This is a living document - if you see something out of date or missing, speak up!
|
||||
#
|
||||
# It is structured to be consumable by both humans and programs.
|
||||
# To extract its contents programmatically, use any TOML-compliant
|
||||
# parser.
|
||||
#
|
||||
# This file is compiled into the MAINTAINERS file in docker/opensource.
|
||||
#
|
||||
[Org]
|
||||
|
||||
[Org."Core maintainers"]
|
||||
|
||||
# The Core maintainers are the ghostbusters of the project: when there's a problem others
|
||||
# can't solve, they show up and fix it with bizarre devices and weaponry.
|
||||
# They have final say on technical implementation and coding style.
|
||||
# They are ultimately responsible for quality in all its forms: usability polish,
|
||||
# bugfixes, performance, stability, etc. When ownership can cleanly be passed to
|
||||
# a subsystem, they are responsible for doing so and holding the
|
||||
# subsystem maintainers accountable. If ownership is unclear, they are the de facto owners.
|
||||
|
||||
people = [
|
||||
"glours",
|
||||
"jhrotko",
|
||||
"milas",
|
||||
"ndeloof",
|
||||
"nicksieger",
|
||||
"StefanScherer",
|
||||
"ulyssessouza"
|
||||
]
|
||||
|
||||
[Org."Regular maintainers"]
|
||||
# The Regular maintainers are people who aren't Core maintainers but are around
|
||||
# to help reviewing and fixing bugs, just on a less regular basis than previously.
|
||||
# Most of them were previously Core maintainers of Compose.
|
||||
people = [
|
||||
"aiordache",
|
||||
"chris-crone",
|
||||
"gtardif",
|
||||
"laurazard",
|
||||
"maxcleme",
|
||||
"rumpl",
|
||||
"thaJeztah"
|
||||
]
|
||||
|
||||
[people]
|
||||
|
||||
# A reference list of all people associated with the project.
|
||||
# All other sections should refer to people by their canonical key
|
||||
# in the people section.
|
||||
|
||||
# ADD YOURSELF HERE IN ALPHABETICAL ORDER
|
||||
|
||||
[people.aiordache]
|
||||
Name = "Anca Iordache"
|
||||
Email = "anca.iordache@docker.com"
|
||||
GitHub = "aiordache "
|
||||
|
||||
[people.chris-crone]
|
||||
Name = "Christopher Crone"
|
||||
Email = "christopher.crone@docker.com"
|
||||
GitHub = "chris-crone"
|
||||
|
||||
[people.glours]
|
||||
Name = "Guillaume Lours"
|
||||
Email = "guillaume.lours@docker.com"
|
||||
GitHub = "glours"
|
||||
|
||||
[people.gtardif]
|
||||
Name = "Guillaume Tardif"
|
||||
Email = "guillaume.tardif@docker.com"
|
||||
GitHub = "gtardif"
|
||||
|
||||
[people.jhrotko]
|
||||
Name = "Joana Hrotko"
|
||||
Email = "joana.hrotko@docker.com"
|
||||
Github = "jhrotko"
|
||||
|
||||
[people.laurazard]
|
||||
Name = "Laura Brehm"
|
||||
Email = "laura.brehm@docker.com"
|
||||
GitHub = "laurazard"
|
||||
|
||||
[people.maxcleme]
|
||||
Name = "Maxime Clement"
|
||||
Email = "maxime.clement@docker.com"
|
||||
GitHub = "maxcleme"
|
||||
|
||||
[people.milas]
|
||||
Name = "Milas Bowman"
|
||||
Email = "milas.bowman@docker.com"
|
||||
GitHub = "milas"
|
||||
|
||||
[people.nicksieger]
|
||||
Name = "Nick Sieger"
|
||||
Email = "nick.sieger@docker.com"
|
||||
GitHub = "nicksieger"
|
||||
|
||||
[people.ndeloof]
|
||||
Name = "Nicolas Deloof"
|
||||
Email = "nicolas.deloof@docker.com"
|
||||
GitHub = "ndeloof"
|
||||
|
||||
[people.rumpl]
|
||||
Name = "Djordje Lukic"
|
||||
Email = "djordje.lukic@docker.com"
|
||||
GitHub = "rumpl"
|
||||
|
||||
[people.thaJeztah]
|
||||
Name = "Sebastiaan van Stijn"
|
||||
Email = "sebastiaan.vanstijn@docker.com"
|
||||
GitHub = "thaJeztah "
|
||||
|
||||
[people.StefanScherer]
|
||||
Name = "Stefan Scherer"
|
||||
Email = "stefan.scherer@docker.com"
|
||||
GitHub = "StefanScherer"
|
||||
|
||||
[people.ulyssessouza]
|
||||
Name = "Ulysses Souza"
|
||||
Email = "<ulysses.souza@docker.com"
|
||||
Github = "ulyssessouza"
|
||||
6
Makefile
6
Makefile
@@ -74,7 +74,7 @@ install: binary
|
||||
install $(or $(DESTDIR),./bin/build)/docker-compose ~/.docker/cli-plugins/docker-compose
|
||||
|
||||
.PHONY: e2e-compose
|
||||
e2e-compose: ## Run end to end local tests in plugin mode. Set E2E_TEST=TestName to run a single test
|
||||
e2e-compose: example-provider ## Run end to end local tests in plugin mode. Set E2E_TEST=TestName to run a single test
|
||||
go run gotest.tools/gotestsum@latest --format testname --junitfile "/tmp/report/report.xml" -- -v $(TEST_FLAGS) -count=1 ./pkg/e2e
|
||||
|
||||
.PHONY: e2e-compose-standalone
|
||||
@@ -87,6 +87,10 @@ build-and-e2e-compose: build e2e-compose ## Compile the compose cli-plugin and r
|
||||
.PHONY: build-and-e2e-compose-standalone
|
||||
build-and-e2e-compose-standalone: build e2e-compose-standalone ## Compile the compose cli-plugin and run End to end local tests in standalone mode. Set E2E_TEST=TestName to run a single test
|
||||
|
||||
.PHONY: example-provider
|
||||
example-provider: ## build example provider for e2e tests
|
||||
go build -o bin/build/example-provider docs/examples/provider.go
|
||||
|
||||
.PHONY: mocks
|
||||
mocks:
|
||||
mockgen --version >/dev/null 2>&1 || go install go.uber.org/mock/mockgen@v0.4.0
|
||||
|
||||
@@ -23,6 +23,12 @@ your application are configured.
|
||||
Once you have a Compose file, you can create and start your application with a
|
||||
single command: `docker compose up`.
|
||||
|
||||
> **Note**: About Docker Swarm
|
||||
> Docker Swarm used to rely on the legacy compose file format but did not adopted the compose specification
|
||||
> so is missing some of the recent enhancements in the compose syntax. After
|
||||
> [acquisition by Mirantis](https://www.mirantis.com/software/swarm/) swarm isn't maintained by Docker Inc, and
|
||||
> as such some Docker Compose features aren't accessible to swarm users.
|
||||
|
||||
# Where to get Docker Compose
|
||||
|
||||
### Windows and macOS
|
||||
|
||||
@@ -55,8 +55,10 @@ func Setup(cmd *cobra.Command, dockerCli command.Cli, args []string) error {
|
||||
ctx,
|
||||
"cli/"+strings.Join(commandName(cmd), "-"),
|
||||
)
|
||||
cmdSpan.SetAttributes(attribute.StringSlice("cli.flags", getFlags(cmd.Flags())))
|
||||
cmdSpan.SetAttributes(attribute.Bool("cli.isatty", dockerCli.In().IsTerminal()))
|
||||
cmdSpan.SetAttributes(
|
||||
attribute.StringSlice("cli.flags", getFlags(cmd.Flags())),
|
||||
attribute.Bool("cli.isatty", dockerCli.In().IsTerminal()),
|
||||
)
|
||||
|
||||
cmd.SetContext(ctx)
|
||||
wrapRunE(cmd, cmdSpan, tracingShutdown)
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
)
|
||||
|
||||
// alphaCommand groups all experimental subcommands
|
||||
func alphaCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func alphaCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Short: "Experimental commands",
|
||||
Use: "alpha [COMMAND]",
|
||||
|
||||
@@ -35,7 +35,7 @@ type attachOpts struct {
|
||||
proxy bool
|
||||
}
|
||||
|
||||
func attachCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func attachCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := attachOpts{
|
||||
composeOptions: &composeOptions{
|
||||
ProjectOptions: p,
|
||||
@@ -63,7 +63,7 @@ func attachCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
return runCmd
|
||||
}
|
||||
|
||||
func runAttach(ctx context.Context, dockerCli command.Cli, backend api.Service, opts attachOpts) error {
|
||||
func runAttach(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts attachOpts) error {
|
||||
projectName, err := opts.toProjectName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
149
cmd/compose/bridge.go
Normal file
149
cmd/compose/bridge.go
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/docker/compose/v2/pkg/bridge"
|
||||
)
|
||||
|
||||
func bridgeCommand(p *ProjectOptions, dockerCli command.Cli) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "bridge CMD [OPTIONS]",
|
||||
Short: "Convert compose files into another model",
|
||||
TraverseChildren: true,
|
||||
}
|
||||
cmd.AddCommand(
|
||||
convertCommand(p, dockerCli),
|
||||
transformersCommand(dockerCli),
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func convertCommand(p *ProjectOptions, dockerCli command.Cli) *cobra.Command {
|
||||
convertOpts := bridge.ConvertOptions{}
|
||||
cmd := &cobra.Command{
|
||||
Use: "convert",
|
||||
Short: "Convert compose files to Kubernetes manifests, Helm charts, or another model",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runConvert(ctx, dockerCli, p, convertOpts)
|
||||
}),
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.StringVarP(&convertOpts.Output, "output", "o", "out", "The output directory for the Kubernetes resources")
|
||||
flags.StringArrayVarP(&convertOpts.Transformations, "transformation", "t", nil, "Transformation to apply to compose model (default: docker/compose-bridge-kubernetes)")
|
||||
flags.StringVar(&convertOpts.Templates, "templates", "", "Directory containing transformation templates")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runConvert(ctx context.Context, dockerCli command.Cli, p *ProjectOptions, opts bridge.ConvertOptions) error {
|
||||
project, _, err := p.ToProject(ctx, dockerCli, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return bridge.Convert(ctx, dockerCli, project, opts)
|
||||
}
|
||||
|
||||
func transformersCommand(dockerCli command.Cli) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "transformations CMD [OPTIONS]",
|
||||
Short: "Manage transformation images",
|
||||
}
|
||||
cmd.AddCommand(
|
||||
listTransformersCommand(dockerCli),
|
||||
createTransformerCommand(dockerCli),
|
||||
)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func listTransformersCommand(dockerCli command.Cli) *cobra.Command {
|
||||
options := lsOptions{}
|
||||
cmd := &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List available transformations",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
transformers, err := bridge.ListTransformers(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return displayTransformer(dockerCli, transformers, options)
|
||||
}),
|
||||
}
|
||||
cmd.Flags().StringVar(&options.Format, "format", "table", "Format the output. Values: [table | json]")
|
||||
cmd.Flags().BoolVarP(&options.Quiet, "quiet", "q", false, "Only display transformer names")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func displayTransformer(dockerCli command.Cli, transformers []image.Summary, options lsOptions) error {
|
||||
if options.Quiet {
|
||||
for _, t := range transformers {
|
||||
if len(t.RepoTags) > 0 {
|
||||
_, _ = fmt.Fprintln(dockerCli.Out(), t.RepoTags[0])
|
||||
} else {
|
||||
_, _ = fmt.Fprintln(dockerCli.Out(), t.ID)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return formatter.Print(transformers, options.Format, dockerCli.Out(),
|
||||
func(w io.Writer) {
|
||||
for _, img := range transformers {
|
||||
id := stringid.TruncateID(img.ID)
|
||||
size := units.HumanSizeWithPrecision(float64(img.Size), 3)
|
||||
repo, tag := "<none>", "<none>"
|
||||
if len(img.RepoTags) > 0 {
|
||||
ref, err := reference.ParseDockerRef(img.RepoTags[0])
|
||||
if err == nil {
|
||||
// ParseDockerRef will reject a local image ID
|
||||
repo = reference.FamiliarName(ref)
|
||||
if tagged, ok := ref.(reference.Tagged); ok {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", id, repo, tag, size)
|
||||
}
|
||||
},
|
||||
"IMAGE ID", "REPO", "TAGS", "SIZE")
|
||||
}
|
||||
|
||||
func createTransformerCommand(dockerCli command.Cli) *cobra.Command {
|
||||
var opts bridge.CreateTransformerOptions
|
||||
cmd := &cobra.Command{
|
||||
Use: "create [OPTION] PATH",
|
||||
Short: "Create a new transformation",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
opts.Dest = args[0]
|
||||
return bridge.CreateTransformer(ctx, dockerCli, opts)
|
||||
}),
|
||||
}
|
||||
cmd.Flags().StringVarP(&opts.From, "from", "f", "", "Existing transformation to copy (default: docker/compose-bridge-kubernetes)")
|
||||
return cmd
|
||||
}
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
cliopts "github.com/docker/cli/opts"
|
||||
ui "github.com/docker/compose/v2/pkg/progress"
|
||||
buildkit "github.com/moby/buildkit/util/progress/progressui"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
@@ -46,7 +45,8 @@ type buildOptions struct {
|
||||
deps bool
|
||||
print bool
|
||||
check bool
|
||||
provenance bool
|
||||
sbom string
|
||||
provenance string
|
||||
}
|
||||
|
||||
func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions, error) {
|
||||
@@ -85,11 +85,12 @@ func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions,
|
||||
Check: opts.check,
|
||||
SSHs: SSHKeys,
|
||||
Builder: builderName,
|
||||
SBOM: opts.sbom,
|
||||
Provenance: opts.provenance,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := buildOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -120,12 +121,14 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVar(&opts.push, "push", false, "Push service images")
|
||||
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT")
|
||||
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress the build output")
|
||||
flags.BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image")
|
||||
flags.StringArrayVar(&opts.args, "build-arg", []string{}, "Set build-time variables for services")
|
||||
flags.StringVar(&opts.ssh, "ssh", "", "Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent)")
|
||||
flags.StringVar(&opts.builder, "builder", "", "Set builder to use")
|
||||
flags.BoolVar(&opts.deps, "with-dependencies", false, "Also build dependencies (transitively)")
|
||||
flags.StringVar(&opts.provenance, "provenance", "", `Add a provenance attestation`)
|
||||
flags.StringVar(&opts.sbom, "sbom", "", `Add a SBOM attestation`)
|
||||
|
||||
flags.Bool("parallel", true, "Build images in parallel. DEPRECATED")
|
||||
flags.MarkHidden("parallel") //nolint:errcheck
|
||||
@@ -137,7 +140,7 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
flags.Bool("no-rm", false, "Do not remove intermediate containers after a successful build. DEPRECATED")
|
||||
flags.MarkHidden("no-rm") //nolint:errcheck
|
||||
flags.VarP(&opts.memory, "memory", "m", "Set memory limit for the build container. Not supported by BuildKit.")
|
||||
flags.StringVar(&p.Progress, "progress", string(buildkit.AutoMode), fmt.Sprintf(`Set type of ui output (%s)`, strings.Join(printerModes, ", ")))
|
||||
flags.StringVar(&p.Progress, "progress", "", fmt.Sprintf(`Set type of ui output (%s)`, strings.Join(printerModes, ", ")))
|
||||
flags.MarkHidden("progress") //nolint:errcheck
|
||||
flags.BoolVar(&opts.print, "print", false, "Print equivalent bake file")
|
||||
flags.BoolVar(&opts.check, "check", false, "Check build configuration")
|
||||
@@ -145,7 +148,8 @@ func buildCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runBuild(ctx context.Context, dockerCli command.Cli, backend api.Service, opts buildOptions, services []string) error {
|
||||
func runBuild(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts buildOptions, services []string) error {
|
||||
opts.All = true // do not drop resources as build may involve some dependencies by additional_contexts
|
||||
project, _, err := opts.ToProject(ctx, dockerCli, nil, cli.WithResolvedPaths(true), cli.WithoutEnvironmentResolution)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -156,10 +160,10 @@ func runBuild(ctx context.Context, dockerCli command.Cli, backend api.Service, o
|
||||
}
|
||||
|
||||
apiBuildOptions, err := opts.toAPIBuildOptions(services)
|
||||
apiBuildOptions.Provenance = true
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
apiBuildOptions.Attestations = true
|
||||
|
||||
return backend.Build(ctx, project, apiBuildOptions)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ type commitOptions struct {
|
||||
index int
|
||||
}
|
||||
|
||||
func commitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func commitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
options := commitOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -73,13 +73,13 @@ func commitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runCommit(ctx context.Context, dockerCli command.Cli, backend api.Service, options commitOptions) error {
|
||||
func runCommit(ctx context.Context, dockerCli command.Cli, backend api.Compose, options commitOptions) error {
|
||||
projectName, err := options.toProjectName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
commitOptions := api.CommitOptions{
|
||||
return backend.Commit(ctx, projectName, api.CommitOptions{
|
||||
Service: options.service,
|
||||
Reference: options.reference,
|
||||
Pause: options.pause,
|
||||
@@ -87,7 +87,5 @@ func runCommit(ctx context.Context, dockerCli command.Cli, backend api.Service,
|
||||
Author: options.author,
|
||||
Changes: options.changes,
|
||||
Index: options.index,
|
||||
}
|
||||
|
||||
return backend.Commit(ctx, projectName, commitOptions)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func completeServiceNames(dockerCli command.Cli, p *ProjectOptions) validArgsFn
|
||||
}
|
||||
}
|
||||
|
||||
func completeProjectNames(backend api.Service) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
func completeProjectNames(backend api.Compose) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
list, err := backend.List(cmd.Context(), api.ListOptions{
|
||||
All: true,
|
||||
|
||||
@@ -36,18 +36,15 @@ import (
|
||||
composegoutils "github.com/compose-spec/compose-go/v2/utils"
|
||||
"github.com/docker/buildx/util/logutil"
|
||||
dockercli "github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/cli/cli-plugins/metadata"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/pkg/kvfile"
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/docker/compose/v2/internal/desktop"
|
||||
"github.com/docker/compose/v2/internal/experimental"
|
||||
"github.com/docker/compose/v2/internal/tracing"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
ui "github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/docker/compose/v2/pkg/remote"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
buildkit "github.com/moby/buildkit/util/progress/progressui"
|
||||
"github.com/morikuni/aec"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -92,14 +89,6 @@ func init() {
|
||||
dotenv.RegisterFormat("raw", rawEnv)
|
||||
}
|
||||
|
||||
type Backend interface {
|
||||
api.Service
|
||||
|
||||
SetDesktopClient(cli *desktop.Client)
|
||||
|
||||
SetExperiments(experiments *experimental.State)
|
||||
}
|
||||
|
||||
// Command defines a compose CLI command as a func with args
|
||||
type Command func(context.Context, []string) error
|
||||
|
||||
@@ -230,7 +219,7 @@ func (o *ProjectOptions) addProjectFlags(f *pflag.FlagSet) {
|
||||
f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the, first specified, Compose file)")
|
||||
f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the, first specified, Compose file)")
|
||||
f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
|
||||
f.StringVar(&o.Progress, "progress", defaultStringVar(ComposeProgress, string(buildkit.AutoMode)), fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", ")))
|
||||
f.StringVar(&o.Progress, "progress", os.Getenv(ComposeProgress), fmt.Sprintf(`Set type of progress output (%s)`, strings.Join(printerModes, ", ")))
|
||||
f.BoolVar(&o.All, "all-resources", false, "Include all resources, even those not used by services")
|
||||
_ = f.MarkHidden("workdir")
|
||||
}
|
||||
@@ -242,19 +231,11 @@ func defaultStringArrayVar(env string) []string {
|
||||
})
|
||||
}
|
||||
|
||||
// get default value for a command line flag from the env variable, if the env variable is not set, it returns the provided default value 'def'
|
||||
func defaultStringVar(env, def string) string {
|
||||
if v, ok := os.LookupEnv(env); ok {
|
||||
return v
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func (o *ProjectOptions) projectOrName(ctx context.Context, dockerCli command.Cli, services ...string) (*types.Project, string, error) {
|
||||
name := o.ProjectName
|
||||
var project *types.Project
|
||||
if len(o.ConfigPaths) > 0 || o.ProjectName == "" {
|
||||
p, _, err := o.ToProject(ctx, dockerCli, services, cli.WithDiscardEnvFile)
|
||||
p, _, err := o.ToProject(ctx, dockerCli, services, cli.WithDiscardEnvFile, cli.WithoutEnvironmentResolution)
|
||||
if err != nil {
|
||||
envProjectName := os.Getenv(ComposeProjectName)
|
||||
if envProjectName != "" {
|
||||
@@ -392,32 +373,38 @@ func (o *ProjectOptions) remoteLoaders(dockerCli command.Cli) []loader.ResourceL
|
||||
}
|
||||
|
||||
func (o *ProjectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) {
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
opts := []cli.ProjectOptionsFn{
|
||||
cli.WithWorkingDirectory(o.ProjectDir),
|
||||
// First apply os.Environment, always win
|
||||
cli.WithOsEnv,
|
||||
}
|
||||
|
||||
return cli.NewProjectOptions(o.ConfigPaths,
|
||||
append(po,
|
||||
cli.WithWorkingDirectory(o.ProjectDir),
|
||||
// First apply os.Environment, always win
|
||||
cli.WithOsEnv,
|
||||
// set PWD as this variable is not consistently supported on Windows
|
||||
cli.WithEnv([]string{"PWD=" + pwd}),
|
||||
// Load PWD/.env if present and no explicit --env-file has been set
|
||||
cli.WithEnvFiles(o.EnvFiles...),
|
||||
// read dot env file to populate project environment
|
||||
cli.WithDotEnv,
|
||||
// get compose file path set by COMPOSE_FILE
|
||||
cli.WithConfigFileEnv,
|
||||
// if none was selected, get default compose.yaml file from current dir or parent folder
|
||||
cli.WithDefaultConfigPath,
|
||||
// .. and then, a project directory != PWD maybe has been set so let's load .env file
|
||||
cli.WithEnvFiles(o.EnvFiles...),
|
||||
cli.WithDotEnv,
|
||||
// eventually COMPOSE_PROFILES should have been set
|
||||
cli.WithDefaultProfiles(o.Profiles...),
|
||||
cli.WithName(o.ProjectName))...)
|
||||
if _, present := os.LookupEnv("PWD"); !present {
|
||||
if pwd, err := os.Getwd(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
opts = append(opts, cli.WithEnv([]string{"PWD=" + pwd}))
|
||||
}
|
||||
}
|
||||
|
||||
opts = append(opts,
|
||||
// Load PWD/.env if present and no explicit --env-file has been set
|
||||
cli.WithEnvFiles(o.EnvFiles...),
|
||||
// read dot env file to populate project environment
|
||||
cli.WithDotEnv,
|
||||
// get compose file path set by COMPOSE_FILE
|
||||
cli.WithConfigFileEnv,
|
||||
// if none was selected, get default compose.yaml file from current dir or parent folder
|
||||
cli.WithDefaultConfigPath,
|
||||
// .. and then, a project directory != PWD maybe has been set so let's load .env file
|
||||
cli.WithEnvFiles(o.EnvFiles...),
|
||||
cli.WithDotEnv,
|
||||
// eventually COMPOSE_PROFILES should have been set
|
||||
cli.WithDefaultProfiles(o.Profiles...),
|
||||
cli.WithName(o.ProjectName),
|
||||
)
|
||||
|
||||
return cli.NewProjectOptions(o.ConfigPaths, append(po, opts...)...)
|
||||
}
|
||||
|
||||
// PluginName is the name of the plugin
|
||||
@@ -425,11 +412,11 @@ const PluginName = "compose"
|
||||
|
||||
// RunningAsStandalone detects when running as a standalone program
|
||||
func RunningAsStandalone() bool {
|
||||
return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != PluginName
|
||||
return len(os.Args) < 2 || os.Args[1] != metadata.MetadataSubcommandName && os.Args[1] != PluginName
|
||||
}
|
||||
|
||||
// RootCommand returns the compose command with its child commands
|
||||
func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //nolint:gocyclo
|
||||
func RootCommand(dockerCli command.Cli, backend api.Compose) *cobra.Command { //nolint:gocyclo
|
||||
// filter out useless commandConn.CloseWrite warning message that can occur
|
||||
// when using a remote context that is unreachable: "commandConn.CloseWrite: commandconn: failed to wait: signal: killed"
|
||||
// https://github.com/docker/cli/blob/e1f24d3c93df6752d3c27c8d61d18260f141310c/cli/connhelper/commandconn/commandconn.go#L203-L215
|
||||
@@ -440,7 +427,6 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli
|
||||
"commandConn.CloseRead:",
|
||||
))
|
||||
|
||||
experiments := experimental.NewState()
|
||||
opts := ProjectOptions{}
|
||||
var (
|
||||
ansi string
|
||||
@@ -516,8 +502,7 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli
|
||||
}
|
||||
|
||||
switch opts.Progress {
|
||||
case ui.ModeAuto:
|
||||
ui.Mode = ui.ModeAuto
|
||||
case "", ui.ModeAuto:
|
||||
if ansi == "never" {
|
||||
ui.Mode = ui.ModePlain
|
||||
}
|
||||
@@ -585,27 +570,6 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli
|
||||
}
|
||||
cmd.SetContext(ctx)
|
||||
|
||||
// (6) Desktop integration
|
||||
var desktopCli *desktop.Client
|
||||
if !dryRun {
|
||||
if desktopCli, err = desktop.NewFromDockerClient(ctx, dockerCli); desktopCli != nil {
|
||||
logrus.Debugf("Enabled Docker Desktop integration (experimental) @ %s", desktopCli.Endpoint())
|
||||
backend.SetDesktopClient(desktopCli)
|
||||
} else if err != nil {
|
||||
// not fatal, Compose will still work but behave as though
|
||||
// it's not running as part of Docker Desktop
|
||||
logrus.Debugf("failed to enable Docker Desktop integration: %v", err)
|
||||
} else {
|
||||
logrus.Trace("Docker Desktop integration not enabled")
|
||||
}
|
||||
}
|
||||
|
||||
// (7) experimental features
|
||||
if err := experiments.Load(ctx, desktopCli); err != nil {
|
||||
logrus.Debugf("Failed to query feature flags from Desktop: %v", err)
|
||||
}
|
||||
backend.SetExperiments(experiments)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -645,6 +609,8 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli
|
||||
watchCommand(&opts, dockerCli, backend),
|
||||
publishCommand(&opts, dockerCli, backend),
|
||||
alphaCommand(&opts, dockerCli, backend),
|
||||
bridgeCommand(&opts, dockerCli),
|
||||
volumesCommand(&opts, dockerCli, backend),
|
||||
)
|
||||
|
||||
c.Flags().SetInterspersed(false)
|
||||
@@ -669,6 +635,10 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli
|
||||
"profile",
|
||||
completeProfileNames(dockerCli, &opts),
|
||||
)
|
||||
c.RegisterFlagCompletionFunc( //nolint:errcheck
|
||||
"progress",
|
||||
cobra.FixedCompletions(printerModes, cobra.ShellCompDirectiveNoFileComp),
|
||||
)
|
||||
|
||||
c.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`)
|
||||
c.Flags().IntVar(¶llel, "parallel", -1, `Control max parallelism, -1 for unlimited`)
|
||||
@@ -697,7 +667,7 @@ func setEnvWithDotEnv(opts ProjectOptions) error {
|
||||
return nil
|
||||
}
|
||||
for k, v := range envFromFile {
|
||||
if _, ok := os.LookupEnv(k); !ok {
|
||||
if _, ok := os.LookupEnv(k); !ok && strings.HasPrefix(k, "COMPOSE_") {
|
||||
if err = os.Setenv(k, v); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -713,15 +683,3 @@ var printerModes = []string{
|
||||
ui.ModeJSON,
|
||||
ui.ModeQuiet,
|
||||
}
|
||||
|
||||
func SetUnchangedOption(name string, experimentalFlag bool) bool {
|
||||
var value bool
|
||||
// If the var is defined we use that value first
|
||||
if envVar, ok := os.LookupEnv(name); ok {
|
||||
value = utils.StringToBool(envVar)
|
||||
} else {
|
||||
// if not, we try to get it from experimental feature flag
|
||||
value = experimentalFlag
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
@@ -50,6 +50,8 @@ type configOptions struct {
|
||||
noResolveEnv bool
|
||||
services bool
|
||||
volumes bool
|
||||
networks bool
|
||||
models bool
|
||||
profiles bool
|
||||
images bool
|
||||
hash string
|
||||
@@ -111,6 +113,12 @@ func configCommand(p *ProjectOptions, dockerCli command.Cli) *cobra.Command {
|
||||
if opts.volumes {
|
||||
return runVolumes(ctx, dockerCli, opts)
|
||||
}
|
||||
if opts.networks {
|
||||
return runNetworks(ctx, dockerCli, opts)
|
||||
}
|
||||
if opts.models {
|
||||
return runModels(ctx, dockerCli, opts)
|
||||
}
|
||||
if opts.hash != "" {
|
||||
return runHash(ctx, dockerCli, opts)
|
||||
}
|
||||
@@ -147,6 +155,8 @@ func configCommand(p *ProjectOptions, dockerCli command.Cli) *cobra.Command {
|
||||
|
||||
flags.BoolVar(&opts.services, "services", false, "Print the service names, one per line.")
|
||||
flags.BoolVar(&opts.volumes, "volumes", false, "Print the volume names, one per line.")
|
||||
flags.BoolVar(&opts.networks, "networks", false, "Print the network names, one per line.")
|
||||
flags.BoolVar(&opts.models, "models", false, "Print the model names, one per line.")
|
||||
flags.BoolVar(&opts.profiles, "profiles", false, "Print the profile names, one per line.")
|
||||
flags.BoolVar(&opts.images, "images", false, "Print the image names, one per line.")
|
||||
flags.StringVar(&opts.hash, "hash", "", "Print the service config hash, one per line.")
|
||||
@@ -367,6 +377,30 @@ func runVolumes(ctx context.Context, dockerCli command.Cli, opts configOptions)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runNetworks(ctx context.Context, dockerCli command.Cli, opts configOptions) error {
|
||||
project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for n := range project.Networks {
|
||||
_, _ = fmt.Fprintln(dockerCli.Out(), n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runModels(ctx context.Context, dockerCli command.Cli, opts configOptions) error {
|
||||
project, err := opts.ToProject(ctx, dockerCli, nil, cli.WithoutEnvironmentResolution)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, model := range project.Models {
|
||||
if model.Model != "" {
|
||||
_, _ = fmt.Fprintln(dockerCli.Out(), model.Model)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runHash(ctx context.Context, dockerCli command.Cli, opts configOptions) error {
|
||||
var services []string
|
||||
if opts.hash != "*" {
|
||||
|
||||
@@ -38,7 +38,7 @@ type copyOptions struct {
|
||||
copyUIDGID bool
|
||||
}
|
||||
|
||||
func copyCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func copyCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := copyOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func copyCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return copyCmd
|
||||
}
|
||||
|
||||
func runCopy(ctx context.Context, dockerCli command.Cli, backend api.Service, opts copyOptions) error {
|
||||
func runCopy(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts copyOptions) error {
|
||||
name, err := opts.toProjectName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -51,7 +51,7 @@ type createOptions struct {
|
||||
AssumeYes bool
|
||||
}
|
||||
|
||||
func createCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func createCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := createOptions{}
|
||||
buildOpts := buildOptions{
|
||||
ProjectOptions: p,
|
||||
@@ -95,7 +95,7 @@ func createCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runCreate(ctx context.Context, _ command.Cli, backend api.Service, createOpts createOptions, buildOpts buildOptions, project *types.Project, services []string) error {
|
||||
func runCreate(ctx context.Context, _ command.Cli, backend api.Compose, createOpts createOptions, buildOpts buildOptions, project *types.Project, services []string) error {
|
||||
if err := createOpts.Apply(project); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ type downOptions struct {
|
||||
images string
|
||||
}
|
||||
|
||||
func downCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func downCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := downOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -77,7 +77,7 @@ func downCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return downCmd
|
||||
}
|
||||
|
||||
func runDown(ctx context.Context, dockerCli command.Cli, backend api.Service, opts downOptions, services []string) error {
|
||||
func runDown(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts downOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -29,10 +29,12 @@ import (
|
||||
|
||||
type eventsOpts struct {
|
||||
*composeOptions
|
||||
json bool
|
||||
json bool
|
||||
since string
|
||||
until string
|
||||
}
|
||||
|
||||
func eventsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func eventsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := eventsOpts{
|
||||
composeOptions: &composeOptions{
|
||||
ProjectOptions: p,
|
||||
@@ -48,10 +50,12 @@ func eventsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVar(&opts.json, "json", false, "Output events as a stream of json objects")
|
||||
cmd.Flags().StringVar(&opts.since, "since", "", "Show all events created since timestamp")
|
||||
cmd.Flags().StringVar(&opts.until, "until", "", "Stream events until this timestamp")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runEvents(ctx context.Context, dockerCli command.Cli, backend api.Service, opts eventsOpts, services []string) error {
|
||||
func runEvents(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts eventsOpts, services []string) error {
|
||||
name, err := opts.toProjectName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -59,6 +63,8 @@ func runEvents(ctx context.Context, dockerCli command.Cli, backend api.Service,
|
||||
|
||||
return backend.Events(ctx, name, api.EventsOptions{
|
||||
Services: services,
|
||||
Since: opts.since,
|
||||
Until: opts.until,
|
||||
Consumer: func(event api.Event) error {
|
||||
if opts.json {
|
||||
marshal, err := json.Marshal(map[string]interface{}{
|
||||
|
||||
@@ -18,13 +18,18 @@ package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/compose"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
type execOpts struct {
|
||||
@@ -43,7 +48,7 @@ type execOpts struct {
|
||||
interactive bool
|
||||
}
|
||||
|
||||
func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := execOpts{
|
||||
composeOptions: &composeOptions{
|
||||
ProjectOptions: p,
|
||||
@@ -59,7 +64,15 @@ func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return nil
|
||||
}),
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runExec(ctx, dockerCli, backend, opts)
|
||||
err := runExec(ctx, dockerCli, backend, opts)
|
||||
if err != nil {
|
||||
logrus.Debugf("%v", err)
|
||||
var cliError cli.StatusError
|
||||
if ok := errors.As(err, &cliError); ok {
|
||||
os.Exit(err.(cli.StatusError).StatusCode) //nolint: errorlint
|
||||
}
|
||||
}
|
||||
return err
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
}
|
||||
@@ -69,7 +82,7 @@ func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
runCmd.Flags().IntVar(&opts.index, "index", 0, "Index of the container if service has multiple replicas")
|
||||
runCmd.Flags().BoolVarP(&opts.privileged, "privileged", "", false, "Give extended privileges to the process")
|
||||
runCmd.Flags().StringVarP(&opts.user, "user", "u", "", "Run the command as this user")
|
||||
runCmd.Flags().BoolVarP(&opts.noTty, "no-TTY", "T", !dockerCli.Out().IsTerminal(), "Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY.")
|
||||
runCmd.Flags().BoolVarP(&opts.noTty, "no-tty", "T", !dockerCli.Out().IsTerminal(), "Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY.")
|
||||
runCmd.Flags().StringVarP(&opts.workingDir, "workdir", "w", "", "Path to workdir directory for this command")
|
||||
|
||||
runCmd.Flags().BoolVarP(&opts.interactive, "interactive", "i", true, "Keep STDIN open even if not attached")
|
||||
@@ -78,10 +91,16 @@ func execCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
runCmd.Flags().MarkHidden("tty") //nolint:errcheck
|
||||
|
||||
runCmd.Flags().SetInterspersed(false)
|
||||
runCmd.Flags().SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
if name == "no-TTY" { // legacy
|
||||
name = "no-tty"
|
||||
}
|
||||
return pflag.NormalizedName(name)
|
||||
})
|
||||
return runCmd
|
||||
}
|
||||
|
||||
func runExec(ctx context.Context, dockerCli command.Cli, backend api.Service, opts execOpts) error {
|
||||
func runExec(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts execOpts) error {
|
||||
projectName, err := opts.toProjectName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -109,8 +128,8 @@ func runExec(ctx context.Context, dockerCli command.Cli, backend api.Service, op
|
||||
|
||||
exitCode, err := backend.Exec(ctx, projectName, execOpts)
|
||||
if exitCode != 0 {
|
||||
errMsg := ""
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("exit status %d", exitCode)
|
||||
if err != nil && err.Error() != "" {
|
||||
errMsg = err.Error()
|
||||
}
|
||||
return cli.StatusError{StatusCode: exitCode, Status: errMsg}
|
||||
|
||||
@@ -33,7 +33,7 @@ type exportOptions struct {
|
||||
index int
|
||||
}
|
||||
|
||||
func exportCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func exportCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
options := exportOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -58,7 +58,7 @@ func exportCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runExport(ctx context.Context, dockerCli command.Cli, backend api.Service, options exportOptions) error {
|
||||
func runExport(ctx context.Context, dockerCli command.Cli, backend api.Compose, options exportOptions) error {
|
||||
projectName, err := options.toProjectName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -30,7 +30,7 @@ type generateOptions struct {
|
||||
Format string
|
||||
}
|
||||
|
||||
func generateCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
func generateCommand(p *ProjectOptions, backend api.Compose) *cobra.Command {
|
||||
opts := generateOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func generateCommand(p *ProjectOptions, backend api.Service) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runGenerate(ctx context.Context, backend api.Service, opts generateOptions, containers []string) error {
|
||||
func runGenerate(ctx context.Context, backend api.Compose, opts generateOptions, containers []string) error {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "generate command is EXPERIMENTAL")
|
||||
if len(containers) == 0 {
|
||||
return fmt.Errorf("at least one container must be specified")
|
||||
|
||||
@@ -20,9 +20,12 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/go-units"
|
||||
@@ -30,7 +33,6 @@ import (
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
)
|
||||
|
||||
type imageOptions struct {
|
||||
@@ -39,7 +41,7 @@ type imageOptions struct {
|
||||
Format string
|
||||
}
|
||||
|
||||
func imagesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func imagesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := imageOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -56,7 +58,7 @@ func imagesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service
|
||||
return imgCmd
|
||||
}
|
||||
|
||||
func runImages(ctx context.Context, dockerCli command.Cli, backend api.Service, opts imageOptions, services []string) error {
|
||||
func runImages(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts imageOptions, services []string) error {
|
||||
projectName, err := opts.toProjectName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -76,7 +78,7 @@ func runImages(ctx context.Context, dockerCli command.Cli, backend api.Service,
|
||||
if i := strings.IndexRune(img.ID, ':'); i >= 0 {
|
||||
id = id[i+1:]
|
||||
}
|
||||
if !utils.StringContains(ids, id) {
|
||||
if !slices.Contains(ids, id) {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
@@ -85,14 +87,46 @@ func runImages(ctx context.Context, dockerCli command.Cli, backend api.Service,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if opts.Format == "json" {
|
||||
|
||||
sort.Slice(images, func(i, j int) bool {
|
||||
return images[i].ContainerName < images[j].ContainerName
|
||||
})
|
||||
type img struct {
|
||||
ID string `json:"ID"`
|
||||
ContainerName string `json:"ContainerName"`
|
||||
Repository string `json:"Repository"`
|
||||
Tag string `json:"Tag"`
|
||||
Platform string `json:"Platform"`
|
||||
Size int64 `json:"Size"`
|
||||
LastTagTime time.Time `json:"LastTagTime"`
|
||||
}
|
||||
// Convert map to slice
|
||||
var imageList []img
|
||||
for ctr, i := range images {
|
||||
lastTagTime := i.LastTagTime
|
||||
if lastTagTime.IsZero() {
|
||||
lastTagTime = i.Created
|
||||
}
|
||||
imageList = append(imageList, img{
|
||||
ContainerName: ctr,
|
||||
ID: i.ID,
|
||||
Repository: i.Repository,
|
||||
Tag: i.Tag,
|
||||
Platform: platforms.Format(i.Platform),
|
||||
Size: i.Size,
|
||||
LastTagTime: lastTagTime,
|
||||
})
|
||||
}
|
||||
json, err := formatter.ToJSON(imageList, "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fmt.Fprintln(dockerCli.Out(), json)
|
||||
return err
|
||||
}
|
||||
|
||||
return formatter.Print(images, opts.Format, dockerCli.Out(),
|
||||
func(w io.Writer) {
|
||||
for _, img := range images {
|
||||
for _, container := range slices.Sorted(maps.Keys(images)) {
|
||||
img := images[container]
|
||||
id := stringid.TruncateID(img.ID)
|
||||
size := units.HumanSizeWithPrecision(float64(img.Size), 3)
|
||||
repo := img.Repository
|
||||
@@ -103,8 +137,10 @@ func runImages(ctx context.Context, dockerCli command.Cli, backend api.Service,
|
||||
if tag == "" {
|
||||
tag = "<none>"
|
||||
}
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", img.ContainerName, repo, tag, id, size)
|
||||
created := units.HumanDuration(time.Now().UTC().Sub(img.LastTagTime)) + " ago"
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
|
||||
container, repo, tag, platforms.Format(img.Platform), id, size, created)
|
||||
}
|
||||
},
|
||||
"CONTAINER", "REPOSITORY", "TAG", "IMAGE ID", "SIZE")
|
||||
"CONTAINER", "REPOSITORY", "TAG", "PLATFORM", "IMAGE ID", "SIZE", "CREATED")
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ type killOptions struct {
|
||||
signal string
|
||||
}
|
||||
|
||||
func killCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func killCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := killOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func killCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runKill(ctx context.Context, dockerCli command.Cli, backend api.Service, opts killOptions, services []string) error {
|
||||
func runKill(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts killOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -38,7 +38,7 @@ type lsOptions struct {
|
||||
Filter opts.FilterOpt
|
||||
}
|
||||
|
||||
func listCommand(dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func listCommand(dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
lsOpts := lsOptions{Filter: opts.NewFilterOpt()}
|
||||
lsCmd := &cobra.Command{
|
||||
Use: "ls [OPTIONS]",
|
||||
@@ -61,7 +61,7 @@ var acceptedListFilters = map[string]bool{
|
||||
"name": true,
|
||||
}
|
||||
|
||||
func runList(ctx context.Context, dockerCli command.Cli, backend api.Service, lsOpts lsOptions) error {
|
||||
func runList(ctx context.Context, dockerCli command.Cli, backend api.Compose, lsOpts lsOptions) error {
|
||||
filters := lsOpts.Filter.Value()
|
||||
err := filters.Validate(acceptedListFilters)
|
||||
if err != nil {
|
||||
|
||||
@@ -40,7 +40,7 @@ type logsOptions struct {
|
||||
timestamps bool
|
||||
}
|
||||
|
||||
func logsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func logsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := logsOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -70,7 +70,7 @@ func logsCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return logsCmd
|
||||
}
|
||||
|
||||
func runLogs(ctx context.Context, dockerCli command.Cli, backend api.Service, opts logsOptions, services []string) error {
|
||||
func runLogs(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts logsOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
@@ -29,10 +30,9 @@ import (
|
||||
"github.com/compose-spec/compose-go/v2/template"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/cmd/prompt"
|
||||
"github.com/docker/compose/v2/internal/tracing"
|
||||
ui "github.com/docker/compose/v2/pkg/progress"
|
||||
"github.com/docker/compose/v2/pkg/prompt"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
)
|
||||
|
||||
func applyPlatforms(project *types.Project, buildForSinglePlatform bool) error {
|
||||
@@ -44,7 +44,7 @@ func applyPlatforms(project *types.Project, buildForSinglePlatform bool) error {
|
||||
|
||||
// default platform only applies if the service doesn't specify
|
||||
if defaultPlatform != "" && service.Platform == "" {
|
||||
if len(service.Build.Platforms) > 0 && !utils.StringContains(service.Build.Platforms, defaultPlatform) {
|
||||
if len(service.Build.Platforms) > 0 && !slices.Contains(service.Build.Platforms, defaultPlatform) {
|
||||
return fmt.Errorf("service %q build.platforms does not support value set by DOCKER_DEFAULT_PLATFORM: %s", name, defaultPlatform)
|
||||
}
|
||||
service.Platform = defaultPlatform
|
||||
@@ -52,7 +52,7 @@ func applyPlatforms(project *types.Project, buildForSinglePlatform bool) error {
|
||||
|
||||
if service.Platform != "" {
|
||||
if len(service.Build.Platforms) > 0 {
|
||||
if !utils.StringContains(service.Build.Platforms, service.Platform) {
|
||||
if !slices.Contains(service.Build.Platforms, service.Platform) {
|
||||
return fmt.Errorf("service %q build configuration does not support platform: %s", name, service.Platform)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ type pauseOptions struct {
|
||||
*ProjectOptions
|
||||
}
|
||||
|
||||
func pauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func pauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := pauseOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func pauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runPause(ctx context.Context, dockerCli command.Cli, backend api.Service, opts pauseOptions, services []string) error {
|
||||
func runPause(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts pauseOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -60,7 +60,7 @@ type unpauseOptions struct {
|
||||
*ProjectOptions
|
||||
}
|
||||
|
||||
func unpauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func unpauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := unpauseOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func unpauseCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runUnPause(ctx context.Context, dockerCli command.Cli, backend api.Service, opts unpauseOptions, services []string) error {
|
||||
func runUnPause(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts unpauseOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -35,7 +35,7 @@ type portOptions struct {
|
||||
index int
|
||||
}
|
||||
|
||||
func portCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func portCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := portOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -62,7 +62,7 @@ func portCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runPort(ctx context.Context, dockerCli command.Cli, backend api.Service, opts portOptions, service string) error {
|
||||
func runPort(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts portOptions, service string) error {
|
||||
projectName, err := opts.toProjectName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -20,12 +20,12 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/compose/v2/cmd/formatter"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
cliformatter "github.com/docker/cli/cli/command/formatter"
|
||||
@@ -64,7 +64,7 @@ func (p *psOptions) parseFilter() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := psOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -91,7 +91,7 @@ func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *c
|
||||
return psCmd
|
||||
}
|
||||
|
||||
func runPs(ctx context.Context, dockerCli command.Cli, backend api.Service, services []string, opts psOptions) error {
|
||||
func runPs(ctx context.Context, dockerCli command.Cli, backend api.Compose, services []string, opts psOptions) error {
|
||||
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -101,7 +101,7 @@ func runPs(ctx context.Context, dockerCli command.Cli, backend api.Service, serv
|
||||
names := project.ServiceNames()
|
||||
if len(services) > 0 {
|
||||
for _, service := range services {
|
||||
if !utils.StringContains(names, service) {
|
||||
if !slices.Contains(names, service) {
|
||||
return fmt.Errorf("no such service: %s", service)
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func runPs(ctx context.Context, dockerCli command.Cli, backend api.Service, serv
|
||||
services := []string{}
|
||||
for _, c := range containers {
|
||||
s := c.Service
|
||||
if !utils.StringContains(services, s) {
|
||||
if !slices.Contains(services, s) {
|
||||
services = append(services, s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,10 @@ type publishOptions struct {
|
||||
ociVersion string
|
||||
withEnvironment bool
|
||||
assumeYes bool
|
||||
app bool
|
||||
}
|
||||
|
||||
func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := publishOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -53,6 +54,7 @@ func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic
|
||||
flags.StringVar(&opts.ociVersion, "oci-version", "", "OCI image/artifact specification version (automatically determined by default)")
|
||||
flags.BoolVar(&opts.withEnvironment, "with-env", false, "Include environment variables in the published OCI artifact")
|
||||
flags.BoolVarP(&opts.assumeYes, "yes", "y", false, `Assume "yes" as answer to all prompts`)
|
||||
flags.BoolVar(&opts.app, "app", false, "Published compose application (includes referenced images)")
|
||||
flags.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
// assumeYes was introduced by mistake as `--y`
|
||||
if name == "y" {
|
||||
@@ -65,7 +67,7 @@ func publishCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runPublish(ctx context.Context, dockerCli command.Cli, backend api.Service, opts publishOptions, repository string) error {
|
||||
func runPublish(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts publishOptions, repository string) error {
|
||||
project, metrics, err := opts.ToProject(ctx, dockerCli, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -76,7 +78,8 @@ func runPublish(ctx context.Context, dockerCli command.Cli, backend api.Service,
|
||||
}
|
||||
|
||||
return backend.Publish(ctx, project, repository, api.PublishOptions{
|
||||
ResolveImageDigests: opts.resolveImageDigests,
|
||||
ResolveImageDigests: opts.resolveImageDigests || opts.app,
|
||||
Application: opts.app,
|
||||
OCIVersion: api.OCIVersion(opts.ociVersion),
|
||||
WithEnvironment: opts.withEnvironment,
|
||||
AssumeYes: opts.assumeYes,
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/compose-spec/compose-go/v2/cli"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/morikuni/aec"
|
||||
@@ -41,7 +42,7 @@ type pullOptions struct {
|
||||
policy string
|
||||
}
|
||||
|
||||
func pullCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func pullCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := pullOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -96,8 +97,8 @@ func (opts pullOptions) apply(project *types.Project, services []string) (*types
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func runPull(ctx context.Context, dockerCli command.Cli, backend api.Service, opts pullOptions, services []string) error {
|
||||
project, _, err := opts.ToProject(ctx, dockerCli, services)
|
||||
func runPull(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts pullOptions, services []string) error {
|
||||
project, _, err := opts.ToProject(ctx, dockerCli, services, cli.WithoutEnvironmentResolution)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ type pushOptions struct {
|
||||
Quiet bool
|
||||
}
|
||||
|
||||
func pushCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func pushCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := pushOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func pushCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return pushCmd
|
||||
}
|
||||
|
||||
func runPush(ctx context.Context, dockerCli command.Cli, backend api.Service, opts pushOptions, services []string) error {
|
||||
func runPush(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts pushOptions, services []string) error {
|
||||
project, _, err := opts.ToProject(ctx, dockerCli, services)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -31,7 +31,7 @@ type removeOptions struct {
|
||||
volumes bool
|
||||
}
|
||||
|
||||
func removeCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func removeCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := removeOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -59,7 +59,7 @@ Any data which is not in a volume will be lost.`,
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runRemove(ctx context.Context, dockerCli command.Cli, backend api.Service, opts removeOptions, services []string) error {
|
||||
func runRemove(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts removeOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -33,7 +33,7 @@ type restartOptions struct {
|
||||
noDeps bool
|
||||
}
|
||||
|
||||
func restartCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func restartCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := restartOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func restartCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic
|
||||
return restartCmd
|
||||
}
|
||||
|
||||
func runRestart(ctx context.Context, dockerCli command.Cli, backend api.Service, opts restartOptions, services []string) error {
|
||||
func runRestart(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts restartOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -50,7 +50,6 @@ type runOptions struct {
|
||||
Detach bool
|
||||
Remove bool
|
||||
noTty bool
|
||||
tty bool
|
||||
interactive bool
|
||||
user string
|
||||
workdir string
|
||||
@@ -120,8 +119,8 @@ func (options runOptions) apply(project *types.Project) (*types.Project, error)
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func (options runOptions) getEnvironment() (types.Mapping, error) {
|
||||
environment := types.NewMappingWithEquals(options.environment).Resolve(os.LookupEnv).ToMapping()
|
||||
func (options runOptions) getEnvironment(resolve func(string) (string, bool)) (types.Mapping, error) {
|
||||
environment := types.NewMappingWithEquals(options.environment).Resolve(resolve).ToMapping()
|
||||
for _, file := range options.envFiles {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
@@ -143,7 +142,7 @@ func (options runOptions) getEnvironment() (types.Mapping, error) {
|
||||
return environment, nil
|
||||
}
|
||||
|
||||
func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
options := runOptions{
|
||||
composeOptions: &composeOptions{
|
||||
ProjectOptions: p,
|
||||
@@ -155,6 +154,10 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
|
||||
buildOpts := buildOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
// We remove the attribute from the option struct and use a dedicated var, to limit confusion and avoid anyone to use options.tty.
|
||||
// The tty flag is here for convenience and let user do "docker compose run -it" the same way as they use the "docker run" command.
|
||||
var ttyFlag bool
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "run [OPTIONS] SERVICE [COMMAND] [ARGS...]",
|
||||
Short: "Run a one-off command on a service",
|
||||
@@ -178,9 +181,16 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
|
||||
if cmd.Flags().Changed("no-TTY") {
|
||||
return fmt.Errorf("--tty and --no-TTY can't be used together")
|
||||
} else {
|
||||
options.noTty = !options.tty
|
||||
options.noTty = !ttyFlag
|
||||
}
|
||||
} else if !cmd.Flags().Changed("no-TTY") && !cmd.Flags().Changed("interactive") && !dockerCli.In().IsTerminal() {
|
||||
// while `docker run` requires explicit `-it` flags, Compose enables interactive mode and TTY by default
|
||||
// but when compose is used from a scripr has stdin piped from another command, we just can't
|
||||
// Here, we detect we run "by default" (user didn't passed explicit flags) and disable TTY allocation if
|
||||
// we don't have an actual terminal to attach to for interactive mode
|
||||
options.noTty = true
|
||||
}
|
||||
|
||||
if options.quiet {
|
||||
progress.Mode = progress.ModeQuiet
|
||||
devnull, err := os.Open(os.DevNull)
|
||||
@@ -238,7 +248,7 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
|
||||
flags.BoolVar(&options.removeOrphans, "remove-orphans", false, "Remove containers for services not defined in the Compose file")
|
||||
|
||||
cmd.Flags().BoolVarP(&options.interactive, "interactive", "i", true, "Keep STDIN open even if not attached")
|
||||
cmd.Flags().BoolVarP(&options.tty, "tty", "t", true, "Allocate a pseudo-TTY")
|
||||
cmd.Flags().BoolVarP(&ttyFlag, "tty", "t", true, "Allocate a pseudo-TTY")
|
||||
cmd.Flags().MarkHidden("tty") //nolint:errcheck
|
||||
|
||||
flags.SetNormalizeFunc(normalizeRunFlags)
|
||||
@@ -256,7 +266,7 @@ func normalizeRunFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
return pflag.NormalizedName(name)
|
||||
}
|
||||
|
||||
func runRun(ctx context.Context, backend api.Service, project *types.Project, options runOptions, createOpts createOptions, buildOpts buildOptions, dockerCli command.Cli) error {
|
||||
func runRun(ctx context.Context, backend api.Compose, project *types.Project, options runOptions, createOpts createOptions, buildOpts buildOptions, dockerCli command.Cli) error {
|
||||
project, err := options.apply(project)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -271,22 +281,6 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op
|
||||
return err
|
||||
}
|
||||
|
||||
err = progress.Run(ctx, func(ctx context.Context) error {
|
||||
var buildForDeps *api.BuildOptions
|
||||
if !createOpts.noBuild {
|
||||
// allow dependencies needing build to be implicitly selected
|
||||
bo, err := buildOpts.toAPIBuildOptions(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buildForDeps = &bo
|
||||
}
|
||||
return startDependencies(ctx, backend, *project, buildForDeps, options)
|
||||
}, dockerCli.Err())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
labels := types.Labels{}
|
||||
for _, s := range options.labels {
|
||||
parts := strings.SplitN(s, "=", 2)
|
||||
@@ -298,23 +292,26 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op
|
||||
|
||||
var buildForRun *api.BuildOptions
|
||||
if !createOpts.noBuild {
|
||||
// dependencies have already been started above, so only the service
|
||||
// being run might need to be built at this point
|
||||
bo, err := buildOpts.toAPIBuildOptions([]string{options.Service})
|
||||
bo, err := buildOpts.toAPIBuildOptions(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buildForRun = &bo
|
||||
}
|
||||
|
||||
environment, err := options.getEnvironment()
|
||||
environment, err := options.getEnvironment(project.Environment.Resolve)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// start container and attach to container streams
|
||||
runOpts := api.RunOptions{
|
||||
Build: buildForRun,
|
||||
CreateOptions: api.CreateOptions{
|
||||
Build: buildForRun,
|
||||
RemoveOrphans: options.removeOrphans,
|
||||
IgnoreOrphans: options.ignoreOrphans,
|
||||
QuietPull: options.quietPull,
|
||||
},
|
||||
Name: options.name,
|
||||
Service: options.Service,
|
||||
Command: options.Command,
|
||||
@@ -324,15 +321,14 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op
|
||||
Interactive: options.interactive,
|
||||
WorkingDir: options.workdir,
|
||||
User: options.user,
|
||||
CapAdd: options.capAdd.GetAll(),
|
||||
CapDrop: options.capDrop.GetAll(),
|
||||
CapAdd: options.capAdd.GetSlice(),
|
||||
CapDrop: options.capDrop.GetSlice(),
|
||||
Environment: environment.Values(),
|
||||
Entrypoint: options.entrypointCmd,
|
||||
Labels: labels,
|
||||
UseNetworkAliases: options.useAliases,
|
||||
NoDeps: options.noDeps,
|
||||
Index: 0,
|
||||
QuietPull: options.quietPull,
|
||||
}
|
||||
|
||||
for name, service := range project.Services {
|
||||
@@ -352,34 +348,3 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func startDependencies(ctx context.Context, backend api.Service, project types.Project, buildOpts *api.BuildOptions, options runOptions) error {
|
||||
dependencies := types.Services{}
|
||||
var requestedService types.ServiceConfig
|
||||
for name, service := range project.Services {
|
||||
if name != options.Service {
|
||||
dependencies[name] = service
|
||||
} else {
|
||||
requestedService = service
|
||||
}
|
||||
}
|
||||
|
||||
project.Services = dependencies
|
||||
project.DisabledServices[options.Service] = requestedService
|
||||
err := backend.Create(ctx, &project, api.CreateOptions{
|
||||
Build: buildOpts,
|
||||
IgnoreOrphans: options.ignoreOrphans,
|
||||
RemoveOrphans: options.removeOrphans,
|
||||
QuietPull: options.quietPull,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(dependencies) > 0 {
|
||||
return backend.Start(ctx, project.Name, api.StartOptions{
|
||||
Project: &project,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -19,14 +19,13 @@ package compose
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -36,7 +35,7 @@ type scaleOptions struct {
|
||||
noDeps bool
|
||||
}
|
||||
|
||||
func scaleCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func scaleCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := scaleOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -59,8 +58,8 @@ func scaleCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return scaleCmd
|
||||
}
|
||||
|
||||
func runScale(ctx context.Context, dockerCli command.Cli, backend api.Service, opts scaleOptions, serviceReplicaTuples map[string]int) error {
|
||||
services := maps.Keys(serviceReplicaTuples)
|
||||
func runScale(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts scaleOptions, serviceReplicaTuples map[string]int) error {
|
||||
services := slices.Sorted(maps.Keys(serviceReplicaTuples))
|
||||
project, _, err := opts.ToProject(ctx, dockerCli, services)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -28,7 +28,7 @@ type startOptions struct {
|
||||
*ProjectOptions
|
||||
}
|
||||
|
||||
func startCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func startCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := startOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func startCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return startCmd
|
||||
}
|
||||
|
||||
func runStart(ctx context.Context, dockerCli command.Cli, backend api.Service, opts startOptions, services []string) error {
|
||||
func runStart(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts startOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -32,7 +32,7 @@ type stopOptions struct {
|
||||
timeout int
|
||||
}
|
||||
|
||||
func stopCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func stopCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := stopOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func stopCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runStop(ctx context.Context, dockerCli command.Cli, backend api.Service, opts stopOptions, services []string) error {
|
||||
func runStop(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts stopOptions, services []string) error {
|
||||
project, name, err := opts.projectOrName(ctx, dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -34,7 +34,7 @@ type topOptions struct {
|
||||
*ProjectOptions
|
||||
}
|
||||
|
||||
func topCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func topCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := topOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -54,7 +54,7 @@ type (
|
||||
topEntries map[string]string
|
||||
)
|
||||
|
||||
func runTop(ctx context.Context, dockerCli command.Cli, backend api.Service, opts topOptions, services []string) error {
|
||||
func runTop(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts topOptions, services []string) error {
|
||||
projectName, err := opts.toProjectName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -202,7 +202,7 @@ var topTestCases = []struct {
|
||||
}
|
||||
|
||||
// TestRunTopCore only tests the core functionality of runTop: formatting
|
||||
// and printing of the output of (api.Service).Top().
|
||||
// and printing of the output of (api.Compose).Top().
|
||||
func TestRunTopCore(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ func (opts upOptions) OnExit() api.Cascade {
|
||||
}
|
||||
}
|
||||
|
||||
func upCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func upCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
up := upOptions{}
|
||||
create := createOptions{}
|
||||
build := buildOptions{ProjectOptions: p}
|
||||
@@ -165,6 +165,7 @@ func upCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *c
|
||||
flags.BoolVar(&create.recreateDeps, "always-recreate-deps", false, "Recreate dependent containers. Incompatible with --no-recreate.")
|
||||
flags.BoolVarP(&create.noInherit, "renew-anon-volumes", "V", false, "Recreate anonymous volumes instead of retrieving data from the previous containers")
|
||||
flags.BoolVar(&create.quietPull, "quiet-pull", false, "Pull without printing progress information")
|
||||
flags.BoolVar(&build.quiet, "quiet-build", false, "Suppress the build output")
|
||||
flags.StringArrayVar(&up.attach, "attach", []string{}, "Restrict attaching to the specified services. Incompatible with --attach-dependencies.")
|
||||
flags.StringArrayVar(&up.noAttach, "no-attach", []string{}, "Do not attach (stream logs) to the specified services")
|
||||
flags.BoolVar(&up.attachDependencies, "attach-dependencies", false, "Automatically attach to log output of dependent services")
|
||||
@@ -223,10 +224,11 @@ func validateFlags(up *upOptions, create *createOptions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func runUp(
|
||||
ctx context.Context,
|
||||
dockerCli command.Cli,
|
||||
backend api.Service,
|
||||
backend api.Compose,
|
||||
createOptions createOptions,
|
||||
upOptions upOptions,
|
||||
buildOptions buildOptions,
|
||||
@@ -261,6 +263,7 @@ func runUp(
|
||||
return err
|
||||
}
|
||||
bo.Services = services
|
||||
bo.Deps = !upOptions.noDeps
|
||||
build = &bo
|
||||
}
|
||||
|
||||
@@ -329,7 +332,7 @@ func runUp(
|
||||
WaitTimeout: timeout,
|
||||
Watch: upOptions.watch,
|
||||
Services: services,
|
||||
NavigationMenu: upOptions.navigationMenu && ui.Mode != "plain",
|
||||
NavigationMenu: upOptions.navigationMenu && ui.Mode != "plain" && dockerCli.In().IsTerminal(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ type vizOptions struct {
|
||||
indentationStr string
|
||||
}
|
||||
|
||||
func vizCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func vizCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := vizOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -63,7 +63,7 @@ func vizCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runViz(ctx context.Context, dockerCli command.Cli, backend api.Service, opts *vizOptions) error {
|
||||
func runViz(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts *vizOptions) error {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "viz command is EXPERIMENTAL")
|
||||
project, _, err := opts.ToProject(ctx, dockerCli, nil)
|
||||
if err != nil {
|
||||
|
||||
92
cmd/compose/volumes.go
Normal file
92
cmd/compose/volumes.go
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/cli/cli/flags"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type volumesOptions struct {
|
||||
*ProjectOptions
|
||||
Quiet bool
|
||||
Format string
|
||||
}
|
||||
|
||||
func volumesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
options := volumesOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "volumes [OPTIONS] [SERVICE...]",
|
||||
Short: "List volumes",
|
||||
RunE: Adapt(func(ctx context.Context, args []string) error {
|
||||
return runVol(ctx, dockerCli, backend, args, options)
|
||||
}),
|
||||
ValidArgsFunction: completeServiceNames(dockerCli, p),
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVarP(&options.Quiet, "quiet", "q", false, "Only display volume names")
|
||||
cmd.Flags().StringVar(&options.Format, "format", "table", flags.FormatHelp)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runVol(ctx context.Context, dockerCli command.Cli, backend api.Compose, services []string, options volumesOptions) error {
|
||||
project, name, err := options.projectOrName(ctx, dockerCli, services...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if project != nil {
|
||||
names := project.ServiceNames()
|
||||
for _, service := range services {
|
||||
if !slices.Contains(names, service) {
|
||||
return fmt.Errorf("no such service: %s", service)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
volumes, err := backend.Volumes(ctx, name, api.VolumesOptions{
|
||||
Services: services,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.Quiet {
|
||||
for _, v := range volumes {
|
||||
_, _ = fmt.Fprintln(dockerCli.Out(), v.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
volumeCtx := formatter.Context{
|
||||
Output: dockerCli.Out(),
|
||||
Format: formatter.NewVolumeFormat(options.Format, options.Quiet),
|
||||
}
|
||||
|
||||
return formatter.VolumeWrite(volumeCtx, volumes)
|
||||
}
|
||||
@@ -34,7 +34,7 @@ type waitOptions struct {
|
||||
downProject bool
|
||||
}
|
||||
|
||||
func waitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func waitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
opts := waitOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -60,7 +60,7 @@ func waitCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runWait(ctx context.Context, dockerCli command.Cli, backend api.Service, opts *waitOptions) (int64, error) {
|
||||
func runWait(ctx context.Context, dockerCli command.Cli, backend api.Compose, opts *waitOptions) (int64, error) {
|
||||
_, name, err := opts.projectOrName(ctx, dockerCli)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
||||
@@ -36,7 +36,7 @@ type watchOptions struct {
|
||||
noUp bool
|
||||
}
|
||||
|
||||
func watchCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
|
||||
func watchCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Compose) *cobra.Command {
|
||||
watchOpts := watchOptions{
|
||||
ProjectOptions: p,
|
||||
}
|
||||
@@ -64,7 +64,7 @@ func watchCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runWatch(ctx context.Context, dockerCli command.Cli, backend api.Service, watchOpts watchOptions, buildOpts buildOptions, services []string) error {
|
||||
func runWatch(ctx context.Context, dockerCli command.Cli, backend api.Compose, watchOpts watchOptions, buildOpts buildOptions, services []string) error {
|
||||
project, _, err := watchOpts.ToProject(ctx, dockerCli, services)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -117,9 +117,10 @@ func runWatch(ctx context.Context, dockerCli command.Cli, backend api.Service, w
|
||||
}
|
||||
|
||||
consumer := formatter.NewLogConsumer(ctx, dockerCli.Out(), dockerCli.Err(), false, false, false)
|
||||
return backend.Watch(ctx, project, services, api.WatchOptions{
|
||||
Build: &build,
|
||||
LogTo: consumer,
|
||||
Prune: watchOpts.prune,
|
||||
return backend.Watch(ctx, project, api.WatchOptions{
|
||||
Build: &build,
|
||||
LogTo: consumer,
|
||||
Prune: watchOpts.prune,
|
||||
Services: services,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -28,49 +28,42 @@ func ansi(code string) string {
|
||||
return fmt.Sprintf("\033%s", code)
|
||||
}
|
||||
|
||||
func SaveCursor() {
|
||||
func saveCursor() {
|
||||
if disableAnsi {
|
||||
return
|
||||
}
|
||||
fmt.Print(ansi("7"))
|
||||
}
|
||||
|
||||
func RestoreCursor() {
|
||||
func restoreCursor() {
|
||||
if disableAnsi {
|
||||
return
|
||||
}
|
||||
fmt.Print(ansi("8"))
|
||||
}
|
||||
|
||||
func HideCursor() {
|
||||
if disableAnsi {
|
||||
return
|
||||
}
|
||||
fmt.Print(ansi("[?25l"))
|
||||
}
|
||||
|
||||
func ShowCursor() {
|
||||
func showCursor() {
|
||||
if disableAnsi {
|
||||
return
|
||||
}
|
||||
fmt.Print(ansi("[?25h"))
|
||||
}
|
||||
|
||||
func MoveCursor(y, x int) {
|
||||
func moveCursor(y, x int) {
|
||||
if disableAnsi {
|
||||
return
|
||||
}
|
||||
fmt.Print(ansi(fmt.Sprintf("[%d;%dH", y, x)))
|
||||
}
|
||||
|
||||
func MoveCursorX(pos int) {
|
||||
func carriageReturn() {
|
||||
if disableAnsi {
|
||||
return
|
||||
}
|
||||
fmt.Print(ansi(fmt.Sprintf("[%dG", pos)))
|
||||
fmt.Print(ansi(fmt.Sprintf("[%dG", 0)))
|
||||
}
|
||||
|
||||
func ClearLine() {
|
||||
func clearLine() {
|
||||
if disableAnsi {
|
||||
return
|
||||
}
|
||||
@@ -78,7 +71,7 @@ func ClearLine() {
|
||||
fmt.Print(ansi("[2K"))
|
||||
}
|
||||
|
||||
func MoveCursorUp(lines int) {
|
||||
func moveCursorUp(lines int) {
|
||||
if disableAnsi {
|
||||
return
|
||||
}
|
||||
@@ -86,7 +79,7 @@ func MoveCursorUp(lines int) {
|
||||
fmt.Print(ansi(fmt.Sprintf("[%dA", lines)))
|
||||
}
|
||||
|
||||
func MoveCursorDown(lines int) {
|
||||
func moveCursorDown(lines int) {
|
||||
if disableAnsi {
|
||||
return
|
||||
}
|
||||
@@ -94,7 +87,7 @@ func MoveCursorDown(lines int) {
|
||||
fmt.Print(ansi(fmt.Sprintf("[%dB", lines)))
|
||||
}
|
||||
|
||||
func NewLine() {
|
||||
func newLine() {
|
||||
// Like \n
|
||||
fmt.Print("\012")
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package formatter
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
@@ -58,6 +59,9 @@ const (
|
||||
Auto = "auto"
|
||||
)
|
||||
|
||||
// ansiColorOffset is the offset for basic foreground colors in ANSI escape codes.
|
||||
const ansiColorOffset = 30
|
||||
|
||||
// SetANSIMode configure formatter for colored output on ANSI-compliant console
|
||||
func SetANSIMode(streams command.Streams, ansi string) {
|
||||
if !useAnsi(streams, ansi) {
|
||||
@@ -91,11 +95,15 @@ func ansiColor(code, s string, formatOpts ...string) string {
|
||||
|
||||
// Everything about ansiColorCode color https://hyperskill.org/learn/step/18193
|
||||
func ansiColorCode(code string, formatOpts ...string) string {
|
||||
res := "\033["
|
||||
var sb strings.Builder
|
||||
sb.WriteString("\033[")
|
||||
for _, c := range formatOpts {
|
||||
res = fmt.Sprintf("%s%s;", res, c)
|
||||
sb.WriteString(c)
|
||||
sb.WriteString(";")
|
||||
}
|
||||
return fmt.Sprintf("%s%sm", res, code)
|
||||
sb.WriteString(code)
|
||||
sb.WriteString("m")
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func makeColorFunc(code string) colorFunc {
|
||||
@@ -122,8 +130,8 @@ func rainbowColor() colorFunc {
|
||||
func init() {
|
||||
colors := map[string]colorFunc{}
|
||||
for i, name := range names {
|
||||
colors[name] = makeColorFunc(strconv.Itoa(30 + i))
|
||||
colors["intense_"+name] = makeColorFunc(strconv.Itoa(30+i) + ";1")
|
||||
colors[name] = makeColorFunc(strconv.Itoa(ansiColorOffset + i))
|
||||
colors["intense_"+name] = makeColorFunc(strconv.Itoa(ansiColorOffset+i) + ";1")
|
||||
}
|
||||
rainbow = []colorFunc{
|
||||
colors["cyan"],
|
||||
|
||||
@@ -56,10 +56,6 @@ func NewLogConsumer(ctx context.Context, stdout, stderr io.Writer, color, prefix
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logConsumer) Register(name string) {
|
||||
l.register(name)
|
||||
}
|
||||
|
||||
func (l *logConsumer) register(name string) *presenter {
|
||||
var p *presenter
|
||||
root, _, found := strings.Cut(name, " ")
|
||||
@@ -73,9 +69,12 @@ func (l *logConsumer) register(name string) *presenter {
|
||||
} else {
|
||||
cf := monochrome
|
||||
if l.color {
|
||||
if name == api.WatchLogger {
|
||||
switch name {
|
||||
case "":
|
||||
cf = monochrome
|
||||
case api.WatchLogger:
|
||||
cf = makeColorFunc("92")
|
||||
} else {
|
||||
default:
|
||||
cf = nextColor()
|
||||
}
|
||||
}
|
||||
@@ -118,23 +117,15 @@ func (l *logConsumer) write(w io.Writer, container, message string) {
|
||||
if l.ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
if KeyboardManager != nil {
|
||||
KeyboardManager.ClearKeyboardInfo()
|
||||
}
|
||||
|
||||
p := l.getPresenter(container)
|
||||
timestamp := time.Now().Format(jsonmessage.RFC3339NanoFixed)
|
||||
for _, line := range strings.Split(message, "\n") {
|
||||
if l.timestamp {
|
||||
_, _ = fmt.Fprintf(w, "%s%s%s\n", p.prefix, timestamp, line)
|
||||
_, _ = fmt.Fprintf(w, "%s%s %s\n", p.prefix, timestamp, line)
|
||||
} else {
|
||||
_, _ = fmt.Fprintf(w, "%s%s\n", p.prefix, line)
|
||||
}
|
||||
}
|
||||
|
||||
if KeyboardManager != nil {
|
||||
KeyboardManager.PrintKeyboardInfo()
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logConsumer) Status(container, msg string) {
|
||||
@@ -168,3 +159,27 @@ func (p *presenter) setPrefix(width int) {
|
||||
}
|
||||
p.prefix = p.colors(fmt.Sprintf("%-"+strconv.Itoa(width)+"s | ", p.name))
|
||||
}
|
||||
|
||||
type logDecorator struct {
|
||||
decorated api.LogConsumer
|
||||
Before func()
|
||||
After func()
|
||||
}
|
||||
|
||||
func (l logDecorator) Log(containerName, message string) {
|
||||
l.Before()
|
||||
l.decorated.Log(containerName, message)
|
||||
l.After()
|
||||
}
|
||||
|
||||
func (l logDecorator) Err(containerName, message string) {
|
||||
l.Before()
|
||||
l.decorated.Err(containerName, message)
|
||||
l.After()
|
||||
}
|
||||
|
||||
func (l logDecorator) Status(container, msg string) {
|
||||
l.Before()
|
||||
l.decorated.Status(container, msg)
|
||||
l.After()
|
||||
}
|
||||
|
||||
@@ -29,9 +29,7 @@ import (
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/compose/v2/internal/tracing"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/docker/compose/v2/pkg/watch"
|
||||
"github.com/eiannone/keyboard"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/skratchdot/open-golang/open"
|
||||
)
|
||||
|
||||
@@ -50,8 +48,8 @@ func (ke *KeyboardError) printError(height int, info string) {
|
||||
if ke.shouldDisplay() {
|
||||
errMessage := ke.err.Error()
|
||||
|
||||
MoveCursor(height-1-extraLines(info)-extraLines(errMessage), 0)
|
||||
ClearLine()
|
||||
moveCursor(height-1-extraLines(info)-extraLines(errMessage), 0)
|
||||
clearLine()
|
||||
|
||||
fmt.Print(errMessage)
|
||||
}
|
||||
@@ -71,26 +69,14 @@ func (ke *KeyboardError) error() string {
|
||||
}
|
||||
|
||||
type KeyboardWatch struct {
|
||||
Watcher watch.Notify
|
||||
Watching bool
|
||||
WatchFn func(ctx context.Context, doneCh chan bool, project *types.Project, services []string, options api.WatchOptions) error
|
||||
Ctx context.Context
|
||||
Cancel context.CancelFunc
|
||||
Watcher Feature
|
||||
}
|
||||
|
||||
func (kw *KeyboardWatch) isWatching() bool {
|
||||
return kw.Watching
|
||||
}
|
||||
|
||||
func (kw *KeyboardWatch) switchWatching() {
|
||||
kw.Watching = !kw.Watching
|
||||
}
|
||||
|
||||
func (kw *KeyboardWatch) newContext(ctx context.Context) context.CancelFunc {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
kw.Ctx = ctx
|
||||
kw.Cancel = cancel
|
||||
return cancel
|
||||
// Feature is an compose feature that can be started/stopped by a menu command
|
||||
type Feature interface {
|
||||
Start(context.Context) error
|
||||
Stop() error
|
||||
}
|
||||
|
||||
type KEYBOARD_LOG_LEVEL int
|
||||
@@ -103,42 +89,26 @@ const (
|
||||
|
||||
type LogKeyboard struct {
|
||||
kError KeyboardError
|
||||
Watch KeyboardWatch
|
||||
Watch *KeyboardWatch
|
||||
IsDockerDesktopActive bool
|
||||
IsWatchConfigured bool
|
||||
logLevel KEYBOARD_LOG_LEVEL
|
||||
signalChannel chan<- os.Signal
|
||||
}
|
||||
|
||||
var (
|
||||
KeyboardManager *LogKeyboard
|
||||
eg multierror.Group
|
||||
)
|
||||
|
||||
func NewKeyboardManager(ctx context.Context, isDockerDesktopActive, isWatchConfigured bool,
|
||||
sc chan<- os.Signal,
|
||||
watchFn func(ctx context.Context,
|
||||
doneCh chan bool,
|
||||
project *types.Project,
|
||||
services []string,
|
||||
options api.WatchOptions,
|
||||
) error,
|
||||
) {
|
||||
km := LogKeyboard{}
|
||||
km.IsDockerDesktopActive = isDockerDesktopActive
|
||||
km.IsWatchConfigured = isWatchConfigured
|
||||
km.logLevel = INFO
|
||||
|
||||
km.Watch.Watching = false
|
||||
km.Watch.WatchFn = watchFn
|
||||
|
||||
km.signalChannel = sc
|
||||
|
||||
KeyboardManager = &km
|
||||
func NewKeyboardManager(isDockerDesktopActive bool, sc chan<- os.Signal) *LogKeyboard {
|
||||
return &LogKeyboard{
|
||||
IsDockerDesktopActive: isDockerDesktopActive,
|
||||
logLevel: INFO,
|
||||
signalChannel: sc,
|
||||
}
|
||||
}
|
||||
|
||||
func (lk *LogKeyboard) ClearKeyboardInfo() {
|
||||
lk.clearNavigationMenu()
|
||||
func (lk *LogKeyboard) Decorate(l api.LogConsumer) api.LogConsumer {
|
||||
return logDecorator{
|
||||
decorated: l,
|
||||
Before: lk.clearNavigationMenu,
|
||||
After: lk.PrintKeyboardInfo,
|
||||
}
|
||||
}
|
||||
|
||||
func (lk *LogKeyboard) PrintKeyboardInfo() {
|
||||
@@ -163,7 +133,7 @@ func (lk *LogKeyboard) createBuffer(lines int) {
|
||||
|
||||
if lines > 0 {
|
||||
allocateSpace(lines)
|
||||
MoveCursorUp(lines)
|
||||
moveCursorUp(lines)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,17 +146,17 @@ func (lk *LogKeyboard) printNavigationMenu() {
|
||||
height := goterm.Height()
|
||||
menu := lk.navigationMenu()
|
||||
|
||||
MoveCursorX(0)
|
||||
SaveCursor()
|
||||
carriageReturn()
|
||||
saveCursor()
|
||||
|
||||
lk.kError.printError(height, menu)
|
||||
|
||||
MoveCursor(height-extraLines(menu), 0)
|
||||
ClearLine()
|
||||
moveCursor(height-extraLines(menu), 0)
|
||||
clearLine()
|
||||
fmt.Print(menu)
|
||||
|
||||
MoveCursorX(0)
|
||||
RestoreCursor()
|
||||
carriageReturn()
|
||||
restoreCursor()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +179,7 @@ func (lk *LogKeyboard) navigationMenu() string {
|
||||
watchInfo = navColor(" ")
|
||||
}
|
||||
isEnabled := " Enable"
|
||||
if lk.Watch.Watching {
|
||||
if lk.Watch != nil && lk.Watch.Watching {
|
||||
isEnabled = " Disable"
|
||||
}
|
||||
watchInfo = watchInfo + shortcutKeyColor("w") + navColor(isEnabled+" Watch")
|
||||
@@ -218,63 +188,66 @@ func (lk *LogKeyboard) navigationMenu() string {
|
||||
|
||||
func (lk *LogKeyboard) clearNavigationMenu() {
|
||||
height := goterm.Height()
|
||||
MoveCursorX(0)
|
||||
SaveCursor()
|
||||
carriageReturn()
|
||||
saveCursor()
|
||||
|
||||
// ClearLine()
|
||||
// clearLine()
|
||||
for i := 0; i < height; i++ {
|
||||
MoveCursorDown(1)
|
||||
ClearLine()
|
||||
moveCursorDown(1)
|
||||
clearLine()
|
||||
}
|
||||
RestoreCursor()
|
||||
restoreCursor()
|
||||
}
|
||||
|
||||
func (lk *LogKeyboard) openDockerDesktop(ctx context.Context, project *types.Project) {
|
||||
if !lk.IsDockerDesktopActive {
|
||||
return
|
||||
}
|
||||
eg.Go(tracing.EventWrapFuncForErrGroup(ctx, "menu/gui", tracing.SpanOptions{},
|
||||
func(ctx context.Context) error {
|
||||
link := fmt.Sprintf("docker-desktop://dashboard/apps/%s", project.Name)
|
||||
err := open.Run(link)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not open Docker Desktop")
|
||||
lk.keyboardError("View", err)
|
||||
}
|
||||
return err
|
||||
}),
|
||||
)
|
||||
go func() {
|
||||
_ = tracing.EventWrapFuncForErrGroup(ctx, "menu/gui", tracing.SpanOptions{},
|
||||
func(ctx context.Context) error {
|
||||
link := fmt.Sprintf("docker-desktop://dashboard/apps/%s", project.Name)
|
||||
err := open.Run(link)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not open Docker Desktop")
|
||||
lk.keyboardError("View", err)
|
||||
}
|
||||
return err
|
||||
})()
|
||||
}()
|
||||
}
|
||||
|
||||
func (lk *LogKeyboard) openDDComposeUI(ctx context.Context, project *types.Project) {
|
||||
if !lk.IsDockerDesktopActive {
|
||||
return
|
||||
}
|
||||
eg.Go(tracing.EventWrapFuncForErrGroup(ctx, "menu/gui/composeview", tracing.SpanOptions{},
|
||||
func(ctx context.Context) error {
|
||||
link := fmt.Sprintf("docker-desktop://dashboard/docker-compose/%s", project.Name)
|
||||
err := open.Run(link)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not open Docker Desktop Compose UI")
|
||||
lk.keyboardError("View Config", err)
|
||||
}
|
||||
return err
|
||||
}),
|
||||
)
|
||||
go func() {
|
||||
_ = tracing.EventWrapFuncForErrGroup(ctx, "menu/gui/composeview", tracing.SpanOptions{},
|
||||
func(ctx context.Context) error {
|
||||
link := fmt.Sprintf("docker-desktop://dashboard/docker-compose/%s", project.Name)
|
||||
err := open.Run(link)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not open Docker Desktop Compose UI")
|
||||
lk.keyboardError("View Config", err)
|
||||
}
|
||||
return err
|
||||
})()
|
||||
}()
|
||||
}
|
||||
|
||||
func (lk *LogKeyboard) openDDWatchDocs(ctx context.Context, project *types.Project) {
|
||||
eg.Go(tracing.EventWrapFuncForErrGroup(ctx, "menu/gui/watch", tracing.SpanOptions{},
|
||||
func(ctx context.Context) error {
|
||||
link := fmt.Sprintf("docker-desktop://dashboard/docker-compose/%s/watch", project.Name)
|
||||
err := open.Run(link)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not open Docker Desktop Compose UI")
|
||||
lk.keyboardError("Watch Docs", err)
|
||||
}
|
||||
return err
|
||||
}),
|
||||
)
|
||||
go func() {
|
||||
_ = tracing.EventWrapFuncForErrGroup(ctx, "menu/gui/watch", tracing.SpanOptions{},
|
||||
func(ctx context.Context) error {
|
||||
link := fmt.Sprintf("docker-desktop://dashboard/docker-compose/%s/watch", project.Name)
|
||||
err := open.Run(link)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not open Docker Desktop Compose UI")
|
||||
lk.keyboardError("Watch Docs", err)
|
||||
}
|
||||
return err
|
||||
})()
|
||||
}()
|
||||
}
|
||||
|
||||
func (lk *LogKeyboard) keyboardError(prefix string, err error) {
|
||||
@@ -288,58 +261,54 @@ func (lk *LogKeyboard) keyboardError(prefix string, err error) {
|
||||
}()
|
||||
}
|
||||
|
||||
func (lk *LogKeyboard) StartWatch(ctx context.Context, doneCh chan bool, project *types.Project, options api.UpOptions) {
|
||||
if !lk.IsWatchConfigured {
|
||||
func (lk *LogKeyboard) ToggleWatch(ctx context.Context, options api.UpOptions) {
|
||||
if lk.Watch == nil {
|
||||
return
|
||||
}
|
||||
lk.Watch.switchWatching()
|
||||
if !lk.Watch.isWatching() {
|
||||
lk.Watch.Cancel()
|
||||
if lk.Watch.Watching {
|
||||
err := lk.Watch.Watcher.Stop()
|
||||
if err != nil {
|
||||
options.Start.Attach.Err(api.WatchLogger, err.Error())
|
||||
} else {
|
||||
lk.Watch.Watching = false
|
||||
}
|
||||
} else {
|
||||
eg.Go(tracing.EventWrapFuncForErrGroup(ctx, "menu/watch", tracing.SpanOptions{},
|
||||
func(ctx context.Context) error {
|
||||
if options.Create.Build == nil {
|
||||
err := fmt.Errorf("cannot run watch mode with flag --no-build")
|
||||
lk.keyboardError("Watch", err)
|
||||
go func() {
|
||||
_ = tracing.EventWrapFuncForErrGroup(ctx, "menu/watch", tracing.SpanOptions{},
|
||||
func(ctx context.Context) error {
|
||||
err := lk.Watch.Watcher.Start(ctx)
|
||||
if err != nil {
|
||||
options.Start.Attach.Err(api.WatchLogger, err.Error())
|
||||
} else {
|
||||
lk.Watch.Watching = true
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
lk.Watch.newContext(ctx)
|
||||
buildOpts := *options.Create.Build
|
||||
buildOpts.Quiet = true
|
||||
err := lk.Watch.WatchFn(lk.Watch.Ctx, doneCh, project, options.Start.Services, api.WatchOptions{
|
||||
Build: &buildOpts,
|
||||
LogTo: options.Start.Attach,
|
||||
})
|
||||
if err != nil {
|
||||
lk.Watch.switchWatching()
|
||||
options.Start.Attach.Err(api.WatchLogger, err.Error())
|
||||
}
|
||||
return err
|
||||
}))
|
||||
})()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (lk *LogKeyboard) HandleKeyEvents(event keyboard.KeyEvent, ctx context.Context, doneCh chan bool, project *types.Project, options api.UpOptions) {
|
||||
func (lk *LogKeyboard) HandleKeyEvents(ctx context.Context, event keyboard.KeyEvent, project *types.Project, options api.UpOptions) {
|
||||
switch kRune := event.Rune; kRune {
|
||||
case 'v':
|
||||
lk.openDockerDesktop(ctx, project)
|
||||
case 'w':
|
||||
if !lk.IsWatchConfigured {
|
||||
if lk.Watch == nil {
|
||||
// we try to open watch docs if DD is installed
|
||||
if lk.IsDockerDesktopActive {
|
||||
lk.openDDWatchDocs(ctx, project)
|
||||
}
|
||||
// either way we mark menu/watch as an error
|
||||
eg.Go(tracing.EventWrapFuncForErrGroup(ctx, "menu/watch", tracing.SpanOptions{},
|
||||
func(ctx context.Context) error {
|
||||
err := fmt.Errorf("watch is not yet configured. Learn more: %s", ansiColor(CYAN, "https://docs.docker.com/compose/file-watch/"))
|
||||
lk.keyboardError("Watch", err)
|
||||
return err
|
||||
}))
|
||||
return
|
||||
go func() {
|
||||
_ = tracing.EventWrapFuncForErrGroup(ctx, "menu/watch", tracing.SpanOptions{},
|
||||
func(ctx context.Context) error {
|
||||
err := fmt.Errorf("watch is not yet configured. Learn more: %s", ansiColor(CYAN, "https://docs.docker.com/compose/file-watch/"))
|
||||
lk.keyboardError("Watch", err)
|
||||
return err
|
||||
})()
|
||||
}()
|
||||
}
|
||||
lk.StartWatch(ctx, doneCh, project, options)
|
||||
lk.ToggleWatch(ctx, options)
|
||||
case 'o':
|
||||
lk.openDDComposeUI(ctx, project)
|
||||
}
|
||||
@@ -347,26 +316,31 @@ func (lk *LogKeyboard) HandleKeyEvents(event keyboard.KeyEvent, ctx context.Cont
|
||||
case keyboard.KeyCtrlC:
|
||||
_ = keyboard.Close()
|
||||
lk.clearNavigationMenu()
|
||||
ShowCursor()
|
||||
showCursor()
|
||||
|
||||
lk.logLevel = NONE
|
||||
if lk.Watch.Watching && lk.Watch.Cancel != nil {
|
||||
lk.Watch.Cancel()
|
||||
_ = eg.Wait().ErrorOrNil() // Need to print this ?
|
||||
}
|
||||
// will notify main thread to kill and will handle gracefully
|
||||
lk.signalChannel <- syscall.SIGINT
|
||||
case keyboard.KeyCtrlZ:
|
||||
handleCtrlZ()
|
||||
case keyboard.KeyEnter:
|
||||
NewLine()
|
||||
newLine()
|
||||
lk.printNavigationMenu()
|
||||
}
|
||||
}
|
||||
|
||||
func (lk *LogKeyboard) EnableWatch(enabled bool, watcher Feature) {
|
||||
lk.Watch = &KeyboardWatch{
|
||||
Watching: enabled,
|
||||
Watcher: watcher,
|
||||
}
|
||||
}
|
||||
|
||||
func allocateSpace(lines int) {
|
||||
for i := 0; i < lines; i++ {
|
||||
ClearLine()
|
||||
NewLine()
|
||||
MoveCursorX(0)
|
||||
clearLine()
|
||||
newLine()
|
||||
carriageReturn()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
25
cmd/formatter/shortcut_unix.go
Normal file
25
cmd/formatter/shortcut_unix.go
Normal file
@@ -0,0 +1,25 @@
|
||||
//go:build !windows
|
||||
|
||||
/*
|
||||
Copyright 2024 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package formatter
|
||||
|
||||
import "syscall"
|
||||
|
||||
func handleCtrlZ() {
|
||||
_ = syscall.Kill(0, syscall.SIGSTOP)
|
||||
}
|
||||
25
cmd/formatter/shortcut_windows.go
Normal file
25
cmd/formatter/shortcut_windows.go
Normal file
@@ -0,0 +1,25 @@
|
||||
//go:build windows
|
||||
|
||||
/*
|
||||
Copyright 2024 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package formatter
|
||||
|
||||
// handleCtrlZ is a no-op on Windows as SIGSTOP is not supported
|
||||
func handleCtrlZ() {
|
||||
// Windows doesn't support SIGSTOP/SIGCONT signals
|
||||
// Ctrl+Z behavior is handled differently by the Windows terminal
|
||||
}
|
||||
83
cmd/main.go
83
cmd/main.go
@@ -20,11 +20,11 @@ import (
|
||||
"os"
|
||||
|
||||
dockercli "github.com/docker/cli/cli"
|
||||
"github.com/docker/cli/cli-plugins/manager"
|
||||
"github.com/docker/cli/cli-plugins/metadata"
|
||||
"github.com/docker/cli/cli-plugins/plugin"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/compose/v2/cmd/cmdtrace"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/compose/v2/cmd/prompt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
@@ -35,60 +35,43 @@ import (
|
||||
)
|
||||
|
||||
func pluginMain() {
|
||||
plugin.Run(func(dockerCli command.Cli) *cobra.Command {
|
||||
// TODO(milas): this cast is safe but we should not need to do this,
|
||||
// we should expose the concrete service type so that we do not need
|
||||
// to rely on the `api.Service` interface internally
|
||||
backend := compose.NewComposeService(dockerCli).(commands.Backend)
|
||||
cmd := commands.RootCommand(dockerCli, backend)
|
||||
originalPreRunE := cmd.PersistentPreRunE
|
||||
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
|
||||
// initialize the dockerCli instance
|
||||
if err := plugin.PersistentPreRunE(cmd, args); err != nil {
|
||||
return err
|
||||
}
|
||||
// compose-specific initialization
|
||||
dockerCliPostInitialize(dockerCli)
|
||||
plugin.Run(
|
||||
func(cli command.Cli) *cobra.Command {
|
||||
backend := compose.NewComposeService(cli,
|
||||
compose.WithPrompt(prompt.NewPrompt(cli.In(), cli.Out()).Confirm),
|
||||
)
|
||||
cmd := commands.RootCommand(cli, backend)
|
||||
originalPreRunE := cmd.PersistentPreRunE
|
||||
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
|
||||
// initialize the cli instance
|
||||
if err := plugin.PersistentPreRunE(cmd, args); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmdtrace.Setup(cmd, cli, os.Args[1:]); err != nil {
|
||||
logrus.Debugf("failed to enable tracing: %v", err)
|
||||
}
|
||||
|
||||
if err := cmdtrace.Setup(cmd, dockerCli, os.Args[1:]); err != nil {
|
||||
logrus.Debugf("failed to enable tracing: %v", err)
|
||||
if originalPreRunE != nil {
|
||||
return originalPreRunE(cmd, args)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if originalPreRunE != nil {
|
||||
return originalPreRunE(cmd, args)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd.SetFlagErrorFunc(func(c *cobra.Command, err error) error {
|
||||
return dockercli.StatusError{
|
||||
StatusCode: 1,
|
||||
Status: err.Error(),
|
||||
}
|
||||
})
|
||||
return cmd
|
||||
},
|
||||
manager.Metadata{
|
||||
cmd.SetFlagErrorFunc(func(c *cobra.Command, err error) error {
|
||||
return dockercli.StatusError{
|
||||
StatusCode: 1,
|
||||
Status: err.Error(),
|
||||
}
|
||||
})
|
||||
return cmd
|
||||
},
|
||||
metadata.Metadata{
|
||||
SchemaVersion: "0.1.0",
|
||||
Vendor: "Docker Inc.",
|
||||
Version: internal.Version,
|
||||
})
|
||||
}
|
||||
|
||||
// dockerCliPostInitialize performs Compose-specific configuration for the
|
||||
// command.Cli instance provided by the plugin.Run() initialization.
|
||||
//
|
||||
// NOTE: This must be called AFTER plugin.PersistentPreRunE.
|
||||
func dockerCliPostInitialize(dockerCli command.Cli) {
|
||||
// HACK(milas): remove once docker/cli#4574 is merged; for now,
|
||||
// set it in a rather roundabout way by grabbing the underlying
|
||||
// concrete client and manually invoking an option on it
|
||||
_ = dockerCli.Apply(func(cli *command.DockerCli) error {
|
||||
if mobyClient, ok := cli.Client().(*client.Client); ok {
|
||||
_ = client.WithUserAgent("compose/" + internal.Version)(mobyClient)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
command.WithUserAgent("compose/"+internal.Version),
|
||||
)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Container: github.com/docker/compose-cli/pkg/prompt (interfaces: UI)
|
||||
// Source: github.com/docker/compose-cli/pkg/prompt (interfaces: UI)
|
||||
|
||||
// Package prompt is a generated GoMock package.
|
||||
package prompt
|
||||
@@ -17,11 +17,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -37,34 +39,55 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
type options struct {
|
||||
db string
|
||||
size int
|
||||
}
|
||||
|
||||
func composeCommand() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "compose EVENT",
|
||||
TraverseChildren: true,
|
||||
}
|
||||
c.PersistentFlags().String("project-name", "", "compose project name") // unused
|
||||
c.AddCommand(&cobra.Command{
|
||||
Use: "up",
|
||||
Run: up,
|
||||
|
||||
var options options
|
||||
upCmd := &cobra.Command{
|
||||
Use: "up",
|
||||
Run: func(_ *cobra.Command, args []string) {
|
||||
up(options, args)
|
||||
},
|
||||
Args: cobra.ExactArgs(1),
|
||||
})
|
||||
c.AddCommand(&cobra.Command{
|
||||
}
|
||||
|
||||
upCmd.Flags().StringVar(&options.db, "type", "", "Database type (mysql, postgres, etc.)")
|
||||
_ = upCmd.MarkFlagRequired("type")
|
||||
upCmd.Flags().IntVar(&options.size, "size", 10, "Database size in GB")
|
||||
upCmd.Flags().String("name", "", "Name of the database to be created")
|
||||
_ = upCmd.MarkFlagRequired("name")
|
||||
|
||||
downCmd := &cobra.Command{
|
||||
Use: "down",
|
||||
Run: down,
|
||||
Args: cobra.ExactArgs(1),
|
||||
})
|
||||
}
|
||||
downCmd.Flags().String("name", "", "Name of the database to be deleted")
|
||||
_ = downCmd.MarkFlagRequired("name")
|
||||
|
||||
c.AddCommand(upCmd, downCmd)
|
||||
c.AddCommand(metadataCommand(upCmd, downCmd))
|
||||
return c
|
||||
}
|
||||
|
||||
const lineSeparator = "\n"
|
||||
|
||||
func up(_ *cobra.Command, args []string) {
|
||||
func up(options options, args []string) {
|
||||
servicename := args[0]
|
||||
fmt.Printf(`{ "type": "debug", "message": "Starting %s" }%s`, servicename, lineSeparator)
|
||||
|
||||
for i := 0; i < 100; i += 10 {
|
||||
for i := 0; i < options.size; i += 10 {
|
||||
time.Sleep(1 * time.Second)
|
||||
fmt.Printf(`{ "type": "info", "message": "Processing ... %d%%" }%s`, i, lineSeparator)
|
||||
fmt.Printf(`{ "type": "info", "message": "Processing ... %d%%" }%s`, i*100/options.size, lineSeparator)
|
||||
}
|
||||
fmt.Printf(`{ "type": "setenv", "message": "URL=https://magic.cloud/%s" }%s`, servicename, lineSeparator)
|
||||
}
|
||||
@@ -72,3 +95,58 @@ func up(_ *cobra.Command, args []string) {
|
||||
func down(_ *cobra.Command, _ []string) {
|
||||
fmt.Printf(`{ "type": "error", "message": "Permission error" }%s`, lineSeparator)
|
||||
}
|
||||
|
||||
func metadataCommand(upCmd, downCmd *cobra.Command) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "metadata",
|
||||
Run: func(cmd *cobra.Command, _ []string) {
|
||||
metadata(upCmd, downCmd)
|
||||
},
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
}
|
||||
|
||||
func metadata(upCmd, downCmd *cobra.Command) {
|
||||
metadata := ProviderMetadata{}
|
||||
metadata.Description = "Manage services on AwesomeCloud"
|
||||
metadata.Up = commandParameters(upCmd)
|
||||
metadata.Down = commandParameters(downCmd)
|
||||
jsonMetadata, err := json.Marshal(metadata)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(jsonMetadata))
|
||||
}
|
||||
|
||||
func commandParameters(cmd *cobra.Command) CommandMetadata {
|
||||
cmdMetadata := CommandMetadata{}
|
||||
cmd.Flags().VisitAll(func(f *pflag.Flag) {
|
||||
_, isRequired := f.Annotations[cobra.BashCompOneRequiredFlag]
|
||||
cmdMetadata.Parameters = append(cmdMetadata.Parameters, Metadata{
|
||||
Name: f.Name,
|
||||
Description: f.Usage,
|
||||
Required: isRequired,
|
||||
Type: f.Value.Type(),
|
||||
Default: f.DefValue,
|
||||
})
|
||||
})
|
||||
return cmdMetadata
|
||||
}
|
||||
|
||||
type ProviderMetadata struct {
|
||||
Description string `json:"description"`
|
||||
Up CommandMetadata `json:"up"`
|
||||
Down CommandMetadata `json:"down"`
|
||||
}
|
||||
|
||||
type CommandMetadata struct {
|
||||
Parameters []Metadata `json:"parameters"`
|
||||
}
|
||||
|
||||
type Metadata struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Required bool `json:"required"`
|
||||
Type string `json:"type"`
|
||||
Default string `json:"default,omitempty"`
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ the resource(s) needed to run a service.
|
||||
options:
|
||||
type: mysql
|
||||
size: 256
|
||||
name: myAwesomeCloudDB
|
||||
```
|
||||
|
||||
`provider.type` tells Compose the binary to run, which can be either:
|
||||
@@ -104,8 +105,72 @@ into its runtime environment.
|
||||
## Down lifecycle
|
||||
|
||||
`down` lifecycle is equivalent to `up` with the `<provider> compose --project-name <NAME> down <SERVICE>` command.
|
||||
The provider is responsible for releasing all resources associated with the service.
|
||||
The provider is responsible for releasing all resources associated with the service.
|
||||
|
||||
## Provide metadata about options
|
||||
|
||||
Compose extensions *MAY* optionally implement a `metadata` subcommand to provide information about the parameters accepted by the `up` and `down` commands.
|
||||
|
||||
The `metadata` subcommand takes no parameters and returns a JSON structure on the `stdout` channel that describes the parameters accepted by both the `up` and `down` commands, including whether each parameter is mandatory or optional.
|
||||
|
||||
```console
|
||||
awesomecloud compose metadata
|
||||
```
|
||||
|
||||
The expected JSON output format is:
|
||||
```json
|
||||
{
|
||||
"description": "Manage services on AwesomeCloud",
|
||||
"up": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "type",
|
||||
"description": "Database type (mysql, postgres, etc.)",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"description": "Database size in GB",
|
||||
"required": false,
|
||||
"type": "integer",
|
||||
"default": "10"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"description": "Name of the database to be created",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"down": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "name",
|
||||
"description": "Name of the database to be removed",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
The top elements are:
|
||||
- `description`: Human-readable description of the provider
|
||||
- `up`: Object describing the parameters accepted by the `up` command
|
||||
- `down`: Object describing the parameters accepted by the `down` command
|
||||
|
||||
And for each command parameter, you should include the following properties:
|
||||
- `name`: The parameter name (without `--` prefix)
|
||||
- `description`: Human-readable description of the parameter
|
||||
- `required`: Boolean indicating if the parameter is mandatory
|
||||
- `type`: Parameter type (`string`, `integer`, `boolean`, etc.)
|
||||
- `default`: Default value (optional, only for non-required parameters)
|
||||
- `enum`: List of possible values supported by the parameter separated by `,` (optional, only for parameters with a limited set of values)
|
||||
|
||||
This metadata allows Compose and other tools to understand the provider's interface and provide better user experience, such as validation, auto-completion, and documentation generation.
|
||||
|
||||
## Examples
|
||||
|
||||
See [example](examples/provider.go) for illustration on implementing this API in a command line
|
||||
See [example](examples/provider.go) for illustration on implementing this API in a command line
|
||||
|
||||
@@ -12,6 +12,7 @@ Define and run multi-container applications with Docker
|
||||
| Name | Description |
|
||||
|:--------------------------------|:----------------------------------------------------------------------------------------|
|
||||
| [`attach`](compose_attach.md) | Attach local standard input, output, and error streams to a service's running container |
|
||||
| [`bridge`](compose_bridge.md) | Convert compose files into another model |
|
||||
| [`build`](compose_build.md) | Build or rebuild services |
|
||||
| [`commit`](compose_commit.md) | Create a new image from a service container's changes |
|
||||
| [`config`](compose_config.md) | Parse, resolve and render compose file in canonical format |
|
||||
@@ -42,6 +43,7 @@ Define and run multi-container applications with Docker
|
||||
| [`unpause`](compose_unpause.md) | Unpause services |
|
||||
| [`up`](compose_up.md) | Create and start containers |
|
||||
| [`version`](compose_version.md) | Show the Docker Compose version information |
|
||||
| [`volumes`](compose_volumes.md) | List volumes |
|
||||
| [`wait`](compose_wait.md) | Block until containers of all (or specified) services stop. |
|
||||
| [`watch`](compose_watch.md) | Watch build context for service and rebuild/refresh containers when files are updated |
|
||||
|
||||
@@ -58,7 +60,7 @@ Define and run multi-container applications with Docker
|
||||
| `-f`, `--file` | `stringArray` | | Compose configuration files |
|
||||
| `--parallel` | `int` | `-1` | Control max parallelism, -1 for unlimited |
|
||||
| `--profile` | `stringArray` | | Specify a profile to enable |
|
||||
| `--progress` | `string` | `auto` | Set type of progress output (auto, tty, plain, json, quiet) |
|
||||
| `--progress` | `string` | | Set type of progress output (auto, tty, plain, json, quiet) |
|
||||
| `--project-directory` | `string` | | Specify an alternate working directory<br>(default: the path of the, first specified, Compose file) |
|
||||
| `-p`, `--project-name` | `string` | | Project name |
|
||||
|
||||
|
||||
22
docs/reference/compose_bridge.md
Normal file
22
docs/reference/compose_bridge.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# docker compose bridge
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Convert compose files into another model
|
||||
|
||||
### Subcommands
|
||||
|
||||
| Name | Description |
|
||||
|:-------------------------------------------------------|:-----------------------------------------------------------------------------|
|
||||
| [`convert`](compose_bridge_convert.md) | Convert compose files to Kubernetes manifests, Helm charts, or another model |
|
||||
| [`transformations`](compose_bridge_transformations.md) | Manage transformation images |
|
||||
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:-------|:--------|:--------------------------------|
|
||||
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
17
docs/reference/compose_bridge_convert.md
Normal file
17
docs/reference/compose_bridge_convert.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# docker compose bridge convert
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Convert compose files to Kubernetes manifests, Helm charts, or another model
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:-------------------------|:--------------|:--------|:-------------------------------------------------------------------------------------|
|
||||
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||
| `-o`, `--output` | `string` | `out` | The output directory for the Kubernetes resources |
|
||||
| `--templates` | `string` | | Directory containing transformation templates |
|
||||
| `-t`, `--transformation` | `stringArray` | | Transformation to apply to compose model (default: docker/compose-bridge-kubernetes) |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
22
docs/reference/compose_bridge_transformations.md
Normal file
22
docs/reference/compose_bridge_transformations.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# docker compose bridge transformations
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Manage transformation images
|
||||
|
||||
### Subcommands
|
||||
|
||||
| Name | Description |
|
||||
|:-----------------------------------------------------|:-------------------------------|
|
||||
| [`create`](compose_bridge_transformations_create.md) | Create a new transformation |
|
||||
| [`list`](compose_bridge_transformations_list.md) | List available transformations |
|
||||
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:-------|:--------|:--------------------------------|
|
||||
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
15
docs/reference/compose_bridge_transformations_create.md
Normal file
15
docs/reference/compose_bridge_transformations_create.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# docker compose bridge transformations create
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
Create a new transformation
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:---------------|:---------|:--------|:----------------------------------------------------------------------------|
|
||||
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||
| `-f`, `--from` | `string` | | Existing transformation to copy (default: docker/compose-bridge-kubernetes) |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
20
docs/reference/compose_bridge_transformations_list.md
Normal file
20
docs/reference/compose_bridge_transformations_list.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# docker compose bridge transformations list
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
List available transformations
|
||||
|
||||
### Aliases
|
||||
|
||||
`docker compose bridge transformations list`, `docker compose bridge transformations ls`
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------|:---------|:--------|:-------------------------------------------|
|
||||
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||
| `--format` | `string` | `table` | Format the output. Values: [table \| json] |
|
||||
| `-q`, `--quiet` | `bool` | | Only display transformer names |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -22,9 +22,11 @@ run `docker compose build` to rebuild it.
|
||||
| `-m`, `--memory` | `bytes` | `0` | Set memory limit for the build container. Not supported by BuildKit. |
|
||||
| `--no-cache` | `bool` | | Do not use cache when building the image |
|
||||
| `--print` | `bool` | | Print equivalent bake file |
|
||||
| `--provenance` | `string` | | Add a provenance attestation |
|
||||
| `--pull` | `bool` | | Always attempt to pull a newer version of the image |
|
||||
| `--push` | `bool` | | Push service images |
|
||||
| `-q`, `--quiet` | `bool` | | Don't print anything to STDOUT |
|
||||
| `-q`, `--quiet` | `bool` | | Suppress the build output |
|
||||
| `--sbom` | `string` | | Add a SBOM attestation |
|
||||
| `--ssh` | `string` | | Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent) |
|
||||
| `--with-dependencies` | `bool` | | Also build dependencies (transitively) |
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ the canonical format.
|
||||
| `--hash` | `string` | | Print the service config hash, one per line. |
|
||||
| `--images` | `bool` | | Print the image names, one per line. |
|
||||
| `--lock-image-digests` | `bool` | | Produces an override file with image digests |
|
||||
| `--models` | `bool` | | Print the model names, one per line. |
|
||||
| `--networks` | `bool` | | Print the network names, one per line. |
|
||||
| `--no-consistency` | `bool` | | Don't check model consistency - warning: may produce invalid Compose output |
|
||||
| `--no-env-resolution` | `bool` | | Don't resolve service env files |
|
||||
| `--no-interpolate` | `bool` | | Don't interpolate environment variables |
|
||||
|
||||
@@ -23,10 +23,12 @@ The events that can be received using this can be seen [here](/reference/cli/doc
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:-------|:--------|:------------------------------------------|
|
||||
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||
| `--json` | `bool` | | Output events as a stream of json objects |
|
||||
| Name | Type | Default | Description |
|
||||
|:------------|:---------|:--------|:------------------------------------------|
|
||||
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||
| `--json` | `bool` | | Output events as a stream of json objects |
|
||||
| `--since` | `string` | | Show all events created since timestamp |
|
||||
| `--until` | `string` | | Stream events until this timestamp |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -6,6 +6,12 @@ This is the equivalent of `docker exec` targeting a Compose service.
|
||||
With this subcommand, you can run arbitrary commands in your services. Commands allocate a TTY by default, so
|
||||
you can use a command such as `docker compose exec web sh` to get an interactive prompt.
|
||||
|
||||
By default, Compose will enter container in interactive mode and allocate a TTY, while the equivalent `docker exec`
|
||||
command requires passing `--interactive --tty` flags to get the same behavior. Compose also support those two flags
|
||||
to offer a smooth migration between commands, whenever they are no-op by default. Still, `interactive` can be used to
|
||||
force disabling interactive mode (`--interactive=false`), typically when `docker compose exec` command is used inside
|
||||
a script.
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
@@ -14,7 +20,7 @@ you can use a command such as `docker compose exec web sh` to get an interactive
|
||||
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||
| `-e`, `--env` | `stringArray` | | Set environment variables |
|
||||
| `--index` | `int` | `0` | Index of the container if service has multiple replicas |
|
||||
| `-T`, `--no-TTY` | `bool` | `true` | Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY. |
|
||||
| `-T`, `--no-tty` | `bool` | `true` | Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY. |
|
||||
| `--privileged` | `bool` | | Give extended privileges to the process |
|
||||
| `-u`, `--user` | `string` | | Run the command as this user |
|
||||
| `-w`, `--workdir` | `string` | | Path to workdir directory for this command |
|
||||
@@ -28,3 +34,9 @@ This is the equivalent of `docker exec` targeting a Compose service.
|
||||
|
||||
With this subcommand, you can run arbitrary commands in your services. Commands allocate a TTY by default, so
|
||||
you can use a command such as `docker compose exec web sh` to get an interactive prompt.
|
||||
|
||||
By default, Compose will enter container in interactive mode and allocate a TTY, while the equivalent `docker exec`
|
||||
command requires passing `--interactive --tty` flags to get the same behavior. Compose also support those two flags
|
||||
to offer a smooth migration between commands, whenever they are no-op by default. Still, `interactive` can be used to
|
||||
force disabling interactive mode (`--interactive=false`), typically when `docker compose exec` command is used inside
|
||||
a script.
|
||||
@@ -7,6 +7,7 @@ Publish compose application
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:--------------------------|:---------|:--------|:-------------------------------------------------------------------------------|
|
||||
| `--app` | `bool` | | Published compose application (includes referenced images) |
|
||||
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||
| `--oci-version` | `string` | | OCI image/artifact specification version (automatically determined by default) |
|
||||
| `--resolve-image-digests` | `bool` | | Pin image tags to digests |
|
||||
|
||||
@@ -44,6 +44,7 @@ If the process is interrupted using `SIGINT` (ctrl + C) or `SIGTERM`, the contai
|
||||
| `--no-recreate` | `bool` | | If containers already exist, don't recreate them. Incompatible with --force-recreate. |
|
||||
| `--no-start` | `bool` | | Don't start the services after creating them |
|
||||
| `--pull` | `string` | `policy` | Pull image before running ("always"\|"missing"\|"never") |
|
||||
| `--quiet-build` | `bool` | | Suppress the build output |
|
||||
| `--quiet-pull` | `bool` | | Pull without printing progress information |
|
||||
| `--remove-orphans` | `bool` | | Remove containers for services not defined in the Compose file |
|
||||
| `-V`, `--renew-anon-volumes` | `bool` | | Recreate anonymous volumes instead of retrieving data from the previous containers |
|
||||
|
||||
16
docs/reference/compose_volumes.md
Normal file
16
docs/reference/compose_volumes.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# docker compose volumes
|
||||
|
||||
<!---MARKER_GEN_START-->
|
||||
List volumes
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:----------------|:---------|:--------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `--dry-run` | `bool` | | Execute command in dry run mode |
|
||||
| `--format` | `string` | `table` | Format output using a custom template:<br>'table': Print output in table format with column headers (default)<br>'table TEMPLATE': Print output in table format using the given Go template<br>'json': Print in JSON format<br>'TEMPLATE': Print output using the given Go template.<br>Refer to https://docs.docker.com/go/formatting/ for more information about formatting output with templates |
|
||||
| `-q`, `--quiet` | `bool` | | Only display volume names |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
|
||||
@@ -6,6 +6,7 @@ pname: docker
|
||||
plink: docker.yaml
|
||||
cname:
|
||||
- docker compose attach
|
||||
- docker compose bridge
|
||||
- docker compose build
|
||||
- docker compose commit
|
||||
- docker compose config
|
||||
@@ -36,10 +37,12 @@ cname:
|
||||
- docker compose unpause
|
||||
- docker compose up
|
||||
- docker compose version
|
||||
- docker compose volumes
|
||||
- docker compose wait
|
||||
- docker compose watch
|
||||
clink:
|
||||
- docker_compose_attach.yaml
|
||||
- docker_compose_bridge.yaml
|
||||
- docker_compose_build.yaml
|
||||
- docker_compose_commit.yaml
|
||||
- docker_compose_config.yaml
|
||||
@@ -70,6 +73,7 @@ clink:
|
||||
- docker_compose_unpause.yaml
|
||||
- docker_compose_up.yaml
|
||||
- docker_compose_version.yaml
|
||||
- docker_compose_volumes.yaml
|
||||
- docker_compose_wait.yaml
|
||||
- docker_compose_watch.yaml
|
||||
options:
|
||||
@@ -167,7 +171,6 @@ options:
|
||||
swarm: false
|
||||
- option: progress
|
||||
value_type: string
|
||||
default_value: auto
|
||||
description: Set type of progress output (auto, tty, plain, json, quiet)
|
||||
deprecated: false
|
||||
hidden: false
|
||||
|
||||
@@ -45,7 +45,7 @@ inherited_options:
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
hidden: true
|
||||
experimental: false
|
||||
experimentalcli: true
|
||||
kubernetes: false
|
||||
|
||||
@@ -5,6 +5,16 @@ usage: docker compose alpha publish [OPTIONS] REPOSITORY[:TAG]
|
||||
pname: docker compose alpha
|
||||
plink: docker_compose_alpha.yaml
|
||||
options:
|
||||
- option: app
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Published compose application (includes referenced images)
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: oci-version
|
||||
value_type: string
|
||||
description: |
|
||||
@@ -58,7 +68,7 @@ inherited_options:
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
hidden: true
|
||||
experimental: false
|
||||
experimentalcli: true
|
||||
kubernetes: false
|
||||
|
||||
@@ -69,7 +69,7 @@ inherited_options:
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
hidden: true
|
||||
experimental: false
|
||||
experimentalcli: true
|
||||
kubernetes: false
|
||||
|
||||
29
docs/reference/docker_compose_bridge.yaml
Normal file
29
docs/reference/docker_compose_bridge.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
command: docker compose bridge
|
||||
short: Convert compose files into another model
|
||||
long: Convert compose files into another model
|
||||
pname: docker compose
|
||||
plink: docker_compose.yaml
|
||||
cname:
|
||||
- docker compose bridge convert
|
||||
- docker compose bridge transformations
|
||||
clink:
|
||||
- docker_compose_bridge_convert.yaml
|
||||
- docker_compose_bridge_transformations.yaml
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Execute command in dry run mode
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
|
||||
59
docs/reference/docker_compose_bridge_convert.yaml
Normal file
59
docs/reference/docker_compose_bridge_convert.yaml
Normal file
@@ -0,0 +1,59 @@
|
||||
command: docker compose bridge convert
|
||||
short: |
|
||||
Convert compose files to Kubernetes manifests, Helm charts, or another model
|
||||
long: |
|
||||
Convert compose files to Kubernetes manifests, Helm charts, or another model
|
||||
usage: docker compose bridge convert
|
||||
pname: docker compose bridge
|
||||
plink: docker_compose_bridge.yaml
|
||||
options:
|
||||
- option: output
|
||||
shorthand: o
|
||||
value_type: string
|
||||
default_value: out
|
||||
description: The output directory for the Kubernetes resources
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: templates
|
||||
value_type: string
|
||||
description: Directory containing transformation templates
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: transformation
|
||||
shorthand: t
|
||||
value_type: stringArray
|
||||
default_value: '[]'
|
||||
description: |
|
||||
Transformation to apply to compose model (default: docker/compose-bridge-kubernetes)
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Execute command in dry run mode
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
|
||||
29
docs/reference/docker_compose_bridge_transformations.yaml
Normal file
29
docs/reference/docker_compose_bridge_transformations.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
command: docker compose bridge transformations
|
||||
short: Manage transformation images
|
||||
long: Manage transformation images
|
||||
pname: docker compose bridge
|
||||
plink: docker_compose_bridge.yaml
|
||||
cname:
|
||||
- docker compose bridge transformations create
|
||||
- docker compose bridge transformations list
|
||||
clink:
|
||||
- docker_compose_bridge_transformations_create.yaml
|
||||
- docker_compose_bridge_transformations_list.yaml
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Execute command in dry run mode
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
command: docker compose bridge transformations create
|
||||
short: Create a new transformation
|
||||
long: Create a new transformation
|
||||
usage: docker compose bridge transformations create [OPTION] PATH
|
||||
pname: docker compose bridge transformations
|
||||
plink: docker_compose_bridge_transformations.yaml
|
||||
options:
|
||||
- option: from
|
||||
shorthand: f
|
||||
value_type: string
|
||||
description: |
|
||||
Existing transformation to copy (default: docker/compose-bridge-kubernetes)
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Execute command in dry run mode
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
command: docker compose bridge transformations list
|
||||
aliases: docker compose bridge transformations list, docker compose bridge transformations ls
|
||||
short: List available transformations
|
||||
long: List available transformations
|
||||
usage: docker compose bridge transformations list
|
||||
pname: docker compose bridge transformations
|
||||
plink: docker_compose_bridge_transformations.yaml
|
||||
options:
|
||||
- option: format
|
||||
value_type: string
|
||||
default_value: table
|
||||
description: 'Format the output. Values: [table | json]'
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: quiet
|
||||
shorthand: q
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Only display transformer names
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Execute command in dry run mode
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
|
||||
@@ -118,7 +118,6 @@ options:
|
||||
swarm: false
|
||||
- option: progress
|
||||
value_type: string
|
||||
default_value: auto
|
||||
description: Set type of ui output (auto, tty, plain, json, quiet)
|
||||
deprecated: false
|
||||
hidden: true
|
||||
@@ -126,6 +125,15 @@ options:
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: provenance
|
||||
value_type: string
|
||||
description: Add a provenance attestation
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: pull
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
@@ -150,7 +158,16 @@ options:
|
||||
shorthand: q
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Don't print anything to STDOUT
|
||||
description: Suppress the build output
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: sbom
|
||||
value_type: string
|
||||
description: Add a SBOM attestation
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
|
||||
@@ -56,6 +56,26 @@ options:
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: models
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Print the model names, one per line.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: networks
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Print the network names, one per line.
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: no-consistency
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
|
||||
@@ -34,6 +34,24 @@ options:
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: since
|
||||
value_type: string
|
||||
description: Show all events created since timestamp
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: until
|
||||
value_type: string
|
||||
description: Stream events until this timestamp
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
|
||||
@@ -5,6 +5,12 @@ long: |-
|
||||
|
||||
With this subcommand, you can run arbitrary commands in your services. Commands allocate a TTY by default, so
|
||||
you can use a command such as `docker compose exec web sh` to get an interactive prompt.
|
||||
|
||||
By default, Compose will enter container in interactive mode and allocate a TTY, while the equivalent `docker exec`
|
||||
command requires passing `--interactive --tty` flags to get the same behavior. Compose also support those two flags
|
||||
to offer a smooth migration between commands, whenever they are no-op by default. Still, `interactive` can be used to
|
||||
force disabling interactive mode (`--interactive=false`), typically when `docker compose exec` command is used inside
|
||||
a script.
|
||||
usage: docker compose exec [OPTIONS] SERVICE COMMAND [ARGS...]
|
||||
pname: docker compose
|
||||
plink: docker_compose.yaml
|
||||
@@ -52,7 +58,7 @@ options:
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: no-TTY
|
||||
- option: no-tty
|
||||
shorthand: T
|
||||
value_type: bool
|
||||
default_value: "true"
|
||||
|
||||
@@ -5,6 +5,16 @@ usage: docker compose publish [OPTIONS] REPOSITORY[:TAG]
|
||||
pname: docker compose
|
||||
plink: docker_compose.yaml
|
||||
options:
|
||||
- option: app
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Published compose application (includes referenced images)
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: oci-version
|
||||
value_type: string
|
||||
description: |
|
||||
|
||||
@@ -211,6 +211,16 @@ options:
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: quiet-build
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Suppress the build output
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: quiet-pull
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
|
||||
52
docs/reference/docker_compose_volumes.yaml
Normal file
52
docs/reference/docker_compose_volumes.yaml
Normal file
@@ -0,0 +1,52 @@
|
||||
command: docker compose volumes
|
||||
short: List volumes
|
||||
long: List volumes
|
||||
usage: docker compose volumes [OPTIONS] [SERVICE...]
|
||||
pname: docker compose
|
||||
plink: docker_compose.yaml
|
||||
options:
|
||||
- option: format
|
||||
value_type: string
|
||||
default_value: table
|
||||
description: |-
|
||||
Format output using a custom template:
|
||||
'table': Print output in table format with column headers (default)
|
||||
'table TEMPLATE': Print output in table format using the given Go template
|
||||
'json': Print in JSON format
|
||||
'TEMPLATE': Print output using the given Go template.
|
||||
Refer to https://docs.docker.com/go/formatting/ for more information about formatting output with templates
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
- option: quiet
|
||||
shorthand: q
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Only display volume names
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
inherited_options:
|
||||
- option: dry-run
|
||||
value_type: bool
|
||||
default_value: "false"
|
||||
description: Execute command in dry run mode
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
deprecated: false
|
||||
hidden: false
|
||||
experimental: false
|
||||
experimentalcli: false
|
||||
kubernetes: false
|
||||
swarm: false
|
||||
|
||||
103
go.mod
103
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/docker/compose/v2
|
||||
|
||||
go 1.23.8
|
||||
go 1.24.9
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7
|
||||
@@ -8,27 +8,28 @@ require (
|
||||
github.com/Microsoft/go-winio v0.6.2
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
|
||||
github.com/buger/goterm v1.0.4
|
||||
github.com/compose-spec/compose-go/v2 v2.6.4
|
||||
github.com/containerd/containerd/v2 v2.1.1
|
||||
github.com/compose-spec/compose-go/v2 v2.9.0
|
||||
github.com/containerd/containerd/v2 v2.1.4
|
||||
github.com/containerd/errdefs v1.0.0
|
||||
github.com/containerd/platforms v1.0.0-rc.1
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/distribution/reference v0.6.0
|
||||
github.com/docker/buildx v0.24.0
|
||||
github.com/docker/cli v28.1.1+incompatible
|
||||
github.com/docker/cli-docs-tool v0.9.0
|
||||
github.com/docker/docker v28.1.1+incompatible
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/docker/buildx v0.29.1
|
||||
github.com/docker/cli v28.5.1+incompatible
|
||||
github.com/docker/cli-docs-tool v0.10.0
|
||||
github.com/docker/docker v28.5.1+incompatible
|
||||
github.com/docker/go-connections v0.6.0
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203
|
||||
github.com/fsnotify/fsevents v0.2.0
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hashicorp/go-version v1.7.0
|
||||
github.com/jonboulle/clockwork v0.5.0
|
||||
github.com/mattn/go-shellwords v1.0.12
|
||||
github.com/mitchellh/go-ps v1.0.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/moby/buildkit v0.22.0
|
||||
github.com/moby/buildkit v0.25.1
|
||||
github.com/moby/go-archive v0.1.0
|
||||
github.com/moby/patternmatcher v0.6.0
|
||||
github.com/moby/sys/atomicwriter v0.1.0
|
||||
@@ -39,33 +40,30 @@ require (
|
||||
github.com/otiai10/copy v1.14.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/pflag v1.0.6
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/theupdateframework/notary v0.7.0
|
||||
github.com/spf13/cobra v1.10.1
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0
|
||||
go.opentelemetry.io/otel v1.35.0
|
||||
go.opentelemetry.io/otel v1.36.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0
|
||||
go.opentelemetry.io/otel/metric v1.35.0
|
||||
go.opentelemetry.io/otel/sdk v1.35.0
|
||||
go.opentelemetry.io/otel/trace v1.35.0
|
||||
go.opentelemetry.io/otel/metric v1.36.0
|
||||
go.opentelemetry.io/otel/sdk v1.36.0
|
||||
go.opentelemetry.io/otel/trace v1.36.0
|
||||
go.uber.org/goleak v1.3.0
|
||||
go.uber.org/mock v0.5.2
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0
|
||||
golang.org/x/sync v0.14.0
|
||||
golang.org/x/sys v0.33.0
|
||||
google.golang.org/grpc v1.72.1
|
||||
go.uber.org/mock v0.6.0
|
||||
golang.org/x/sync v0.17.0
|
||||
golang.org/x/sys v0.37.0
|
||||
google.golang.org/grpc v1.74.2
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gotest.tools/v3 v3.5.2
|
||||
tags.cncf.io/container-device-interface v1.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.4.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
|
||||
@@ -83,15 +81,14 @@ require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/containerd/console v1.0.4 // indirect
|
||||
github.com/containerd/console v1.0.5 // indirect
|
||||
github.com/containerd/containerd/api v1.9.0 // indirect
|
||||
github.com/containerd/continuity v0.4.5 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/ttrpc v1.2.7 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.2.3 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
@@ -100,12 +97,11 @@ require (
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fvbommel/sortorder v1.1.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
@@ -113,13 +109,13 @@ require (
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/in-toto/in-toto-golang v0.5.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/in-toto/in-toto-golang v0.9.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
@@ -134,6 +130,7 @@ require (
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/spdystream v0.5.0 // indirect
|
||||
@@ -159,37 +156,37 @@ require (
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.6.0 // indirect
|
||||
github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250417144416-3f76f8130144 // indirect
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250605211040-586307ad452f // indirect
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240814133006-030d3b2625d0 // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
||||
github.com/zclconf/go-cty v1.16.2 // indirect
|
||||
github.com/zclconf/go-cty v1.17.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.31.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.31.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/oauth2 v0.29.0 // indirect
|
||||
golang.org/x/term v0.31.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.38.0 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/term v0.32.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
@@ -205,7 +202,7 @@ require (
|
||||
)
|
||||
|
||||
exclude (
|
||||
// FIXME(thaJeztah): remoove this once kubernetes updated their dependencies to no longer need this.
|
||||
// FIXME(thaJeztah): remove this once kubernetes updated their dependencies to no longer need this.
|
||||
//
|
||||
// For additional details, see this PR and links mentioned in that PR:
|
||||
// https://github.com/kubernetes-sigs/kustomize/pull/5830#issuecomment-2569960859
|
||||
|
||||
201
go.sum
201
go.sum
@@ -1,5 +1,3 @@
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
|
||||
@@ -10,8 +8,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DefangLabs/secret-detector v0.0.0-20250403165618-22662109213e h1:rd4bOvKmDIx0WeTv9Qz+hghsgyjikFiPrseXHlKepO0=
|
||||
github.com/DefangLabs/secret-detector v0.0.0-20250403165618-22662109213e/go.mod h1:blbwPQh4DTlCZEfk1BLU4oMIhLda2U+A840Uag9DsZw=
|
||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
||||
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||
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/hcsshim v0.13.0 h1:/BcXOiS6Qi7N9XqUcv27vkIuVOkBEcWstd2pMlWSeaA=
|
||||
@@ -80,16 +78,16 @@ github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e
|
||||
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
|
||||
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
|
||||
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
|
||||
github.com/compose-spec/compose-go/v2 v2.6.4 h1:Gjv6x8eAhqwwWvoXIo0oZ4bDQBh0OMwdU7LUL9PDLiM=
|
||||
github.com/compose-spec/compose-go/v2 v2.6.4/go.mod h1:vPlkN0i+0LjLf9rv52lodNMUTJF5YHVfHVGLLIP67NA=
|
||||
github.com/compose-spec/compose-go/v2 v2.9.0 h1:UHSv/QHlo6QJtrT4igF1rdORgIUhDo1gWuyJUoiNNIM=
|
||||
github.com/compose-spec/compose-go/v2 v2.9.0/go.mod h1:Oky9AZGTRB4E+0VbTPZTUu4Kp+oEMMuwZXZtPPVT1iE=
|
||||
github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
|
||||
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
|
||||
github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
|
||||
github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
||||
github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
|
||||
github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
||||
github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0=
|
||||
github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI=
|
||||
github.com/containerd/containerd/v2 v2.1.1 h1:znnkm7Ajz8lg8BcIPMhc/9yjBRN3B+OkNKqKisKfwwM=
|
||||
github.com/containerd/containerd/v2 v2.1.1/go.mod h1:zIfkQj4RIodclYQkX7GSSswSwgP8d/XxDOtOAoSDIGU=
|
||||
github.com/containerd/containerd/v2 v2.1.4 h1:/hXWjiSFd6ftrBOBGfAZ6T30LJcx1dBjdKEeI8xucKQ=
|
||||
github.com/containerd/containerd/v2 v2.1.4/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM=
|
||||
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
|
||||
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
|
||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||
@@ -100,8 +98,8 @@ github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY
|
||||
github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/nydus-snapshotter v0.15.0 h1:RqZRs1GPeM6T3wmuxJV9u+2Rg4YETVMwTmiDeX+iWC8=
|
||||
github.com/containerd/nydus-snapshotter v0.15.0/go.mod h1:biq0ijpeZe0I5yZFSJyHzFSjjRZQ7P7y/OuHyd7hYOw=
|
||||
github.com/containerd/nydus-snapshotter v0.15.2 h1:qsHI4M+Wwrf6Jr4eBqhNx8qh+YU0dSiJ+WPmcLFWNcg=
|
||||
github.com/containerd/nydus-snapshotter v0.15.2/go.mod h1:FfwH2KBkNYoisK/e+KsmNr7xTU53DmnavQHMFOcXwfM=
|
||||
github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E=
|
||||
github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
|
||||
github.com/containerd/plugin v1.0.0 h1:c8Kf1TNl6+e2TtMHZt+39yAPDbouRH9WAToRjex483Y=
|
||||
@@ -113,8 +111,9 @@ github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRq
|
||||
github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o=
|
||||
github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40=
|
||||
github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||
@@ -125,24 +124,26 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/buildx v0.24.0 h1:qiD+xktY+Fs3R79oz8M+7pbhip78qGLx6LBuVmyb+64=
|
||||
github.com/docker/buildx v0.24.0/go.mod h1:vYkdBUBjFo/i5vUE0mkajGlk03gE0T/HaGXXhgIxo8E=
|
||||
github.com/docker/cli v28.1.1+incompatible h1:eyUemzeI45DY7eDPuwUcmDyDj1pM98oD5MdSpiItp8k=
|
||||
github.com/docker/cli v28.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli-docs-tool v0.9.0 h1:CVwQbE+ZziwlPqrJ7LRyUF6GvCA+6gj7MTCsayaK9t0=
|
||||
github.com/docker/cli-docs-tool v0.9.0/go.mod h1:ClrwlNW+UioiRyH9GiAOe1o3J/TsY3Tr1ipoypjAUtc=
|
||||
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/docker/buildx v0.29.1 h1:58hxM5Z4mnNje3G5NKfULT9xCr8ooM8XFtlfUK9bKaA=
|
||||
github.com/docker/buildx v0.29.1/go.mod h1:J4EFv6oxlPiV1MjO0VyJx2u5tLM7ImDEl9zyB8d4wPI=
|
||||
github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
|
||||
github.com/docker/cli v28.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli-docs-tool v0.10.0 h1:bOD6mKynPQgojQi3s2jgcUWGp/Ebqy1SeCr9VfKQLLU=
|
||||
github.com/docker/cli-docs-tool v0.10.0/go.mod h1:5EM5zPnT2E7yCLERZmrDA234Vwn09fzRHP4aX1qwp1U=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I=
|
||||
github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
|
||||
github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
||||
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
|
||||
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
||||
@@ -169,8 +170,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
||||
@@ -186,8 +187,8 @@ github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
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/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
@@ -216,8 +217,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
@@ -243,8 +244,8 @@ github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
|
||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
|
||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/in-toto/in-toto-golang v0.5.0 h1:hb8bgwr0M2hGdDsLjkJ3ZqJ8JFLL/tgYdAxF/XEFBbY=
|
||||
github.com/in-toto/in-toto-golang v0.5.0/go.mod h1:/Rq0IZHLV7Ku5gielPT4wPHJfH1GdHMCq8+WPxw8/BE=
|
||||
github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU=
|
||||
github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
@@ -315,8 +316,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 v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/buildkit v0.22.0 h1:aWN06w1YGSVN1XfeZbj2ZbgY+zi5xDAjEFI8Cy9fTjA=
|
||||
github.com/moby/buildkit v0.22.0/go.mod h1:j4pP5hxiTWcz7xuTK2cyxQislHl/N2WWHzOy43DlLJw=
|
||||
github.com/moby/buildkit v0.25.1 h1:j7IlVkeNbEo+ZLoxdudYCHpmTsbwKvhgc/6UJ/mY/o8=
|
||||
github.com/moby/buildkit v0.25.1/go.mod h1:phM8sdqnvgK2y1dPDnbwI6veUCXHOZ6KFSl6E164tkc=
|
||||
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/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
||||
@@ -423,8 +424,10 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.6.0 h1:T65atpAVCJQK14UA57LMdZGpHi4QYSH/9FZyNGqMYIA=
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.6.0/go.mod h1:8Mtpo9JKks/qhPG4HGZ2LGMvrPbzuxwfz/f/zLfEWkk=
|
||||
github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b h1:h+3JX2VoWTFuyQEo87pStk/a99dzIO1mM9KxIyLPGTU=
|
||||
github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc=
|
||||
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
|
||||
@@ -436,18 +439,19 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||
github.com/spdx/tools-golang v0.5.3 h1:ialnHeEYUC4+hkm5vJm4qz2x+oEJbS0mAMFrNXdQraY=
|
||||
github.com/spdx/tools-golang v0.5.3/go.mod h1:/ETOahiAo96Ob0/RAIBmFZw6XN0yTnyr/uFZm2NTMhI=
|
||||
github.com/spdx/tools-golang v0.5.5 h1:61c0KLfAcNqAjlg6UNMdkwpMernhw3zVRwDZ2x9XOmk=
|
||||
github.com/spdx/tools-golang v0.5.5/go.mod h1:MVIsXx8ZZzaRWNQpUDhC4Dud34edUYJYecciXgrw5vE=
|
||||
github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94 h1:JmfC365KywYwHB946TTiQWEb8kqPY+pybPLoGE9GgVk=
|
||||
github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
||||
github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
|
||||
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431 h1:XTHrT015sxHyJ5FnQ0AeemSspZWaDq7DoTRW0EVsDCE=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c h1:2EejZtjFjKJGk71ANb+wtFK5EjUzUkEM3R0xnp559xg=
|
||||
github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -464,18 +468,18 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
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/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375 h1:QB54BJwA6x8QU9nHY3xJSZR2kX9bgpZekRKGkLTmEXA=
|
||||
github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375/go.mod h1:xRroudyp5iVtxKqZCrA6n2TLFRBf8bmnjr1UD4x+z7g=
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 h1:r0p7fK56l8WPequOaR3i9LBqfPtEdXIQbUTzT55iqT4=
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323/go.mod h1:3Iuxbr0P7D3zUzBMAZB+ois3h/et0shEz0qApgHYGpY=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250417144416-3f76f8130144 h1:k9tdF32oJYwtjzMx+D26M6eYiCaAPdJ7tyN7tF1oU5Q=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250417144416-3f76f8130144/go.mod h1:BKdcez7BiVtBvIcef90ZPc6ebqIWr4JWD7+EvLm6J98=
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 h1:7I5c2Ig/5FgqkYOh/N87NzoyI9U15qUPXhDD8uCupv8=
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4/go.mod h1:278M4p8WsNh3n4a1eqiFcV2FGk7wE5fwUpUom9mK9lE=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250605211040-586307ad452f h1:MoxeMfHAe5Qj/ySSBfL8A7l1V+hxuluj8owsIEEZipI=
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250605211040-586307ad452f/go.mod h1:BKdcez7BiVtBvIcef90ZPc6ebqIWr4JWD7+EvLm6J98=
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240814133006-030d3b2625d0 h1:2f304B10LaZdB8kkVEaoXvAMVan2tl9AiK4G0odjQtE=
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240814133006-030d3b2625d0/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/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk=
|
||||
github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab h1:H6aJ0yKQ0gF49Qb2z5hI1UHxSQt4JMyxebFR15KnApw=
|
||||
@@ -484,56 +488,51 @@ github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnn
|
||||
github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zclconf/go-cty v1.16.2 h1:LAJSwc3v81IRBZyUVQDUdZ7hs3SYs9jv0eZJDWHD/70=
|
||||
github.com/zclconf/go-cty v1.16.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
github.com/zclconf/go-cty v1.17.0 h1:seZvECve6XX4tmnvRzWtJNHdscMtYEx5R7bnnVyd/d0=
|
||||
github.com/zclconf/go-cty v1.17.0/go.mod h1:wqFzcImaLTI6A5HfsRwB0nj5n0MRZFwmey8YoFPPs3U=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0 h1:4BZHA+B1wXEQoGNHxW8mURaLhcdGwvRnmhGbm+odRbc=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0/go.mod h1:3qi2EEwMgB4xnKgPLqsDP3j9qxnHDZeHsnAxfjQqTko=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0 h1:0tY123n7CdWMem7MOVdKOt0YfshufLCwfE5Bob+hQuM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0/go.mod h1:CosX/aS4eHnG9D7nESYpV753l4j9q5j3SL/PUYd2lR8=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.31.0 h1:FZ6ei8GFW7kyPYdxJaV2rgI6M+4tvZzhYsQ2wgyVC08=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.31.0/go.mod h1:MdEu/mC6j3D+tTEfvI15b5Ci2Fn7NneJ71YMoiS3tpI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.31.0 h1:ZsXq73BERAiNuuFXYqP4MR5hBrjXfMGSO+Cx7qoOZiM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.31.0/go.mod h1:hg1zaDMpyZJuUzjFxFsRYBoccE86tM9Uf4IqNMUxvrY=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0/go.mod h1:CXIWhUomyWBG/oY2/r/kLp6K/cmx9e/7DLpBuuGdLCA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.35.0 h1:0NIXxOCFx+SKbhCVxwl3ETG8ClLPAa0KuKV6p3yhxP8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.35.0/go.mod h1:ChZSJbbfbl/DcRZNc9Gqh6DYGlfjw4PvO1pEOZH1ZsE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
@@ -542,15 +541,13 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh
|
||||
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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -560,10 +557,10 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
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.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -571,8 +568,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -594,19 +591,19 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -614,21 +611,21 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
|
||||
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a h1:SGktgSolFCo75dnHJF2yMvnns6jCmHFJ0vE4Vn2JKvQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
||||
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package desktop
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
)
|
||||
|
||||
// engineLabelDesktopAddress is used to detect that Compose is running with a
|
||||
// Docker Desktop context. When this label is present, the value is an endpoint
|
||||
// address for an in-memory socket (AF_UNIX or named pipe).
|
||||
const engineLabelDesktopAddress = "com.docker.desktop.address"
|
||||
|
||||
// NewFromDockerClient creates a Desktop Client using the Docker CLI client to
|
||||
// auto-discover the Desktop CLI socket endpoint (if available).
|
||||
//
|
||||
// An error is returned if there is a failure communicating with Docker Desktop,
|
||||
// but even on success, a nil Client can be returned if the active Docker Engine
|
||||
// is not a Desktop instance.
|
||||
func NewFromDockerClient(ctx context.Context, dockerCli command.Cli) (*Client, error) {
|
||||
// safeguard to make sure this doesn't get stuck indefinitely
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second)
|
||||
defer cancel()
|
||||
|
||||
info, err := dockerCli.Client().Info(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying server info: %w", err)
|
||||
}
|
||||
for _, l := range info.Labels {
|
||||
k, v, ok := strings.Cut(l, "=")
|
||||
if !ok || k != engineLabelDesktopAddress {
|
||||
continue
|
||||
}
|
||||
|
||||
desktopCli := NewClient(v)
|
||||
_, err := desktopCli.Ping(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pinging Desktop API: %w", err)
|
||||
}
|
||||
return desktopCli, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build linux || openbsd
|
||||
//go:build linux || openbsd || freebsd
|
||||
|
||||
/*
|
||||
Copyright 2020 Docker Compose CLI authors
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ocipush
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -23,11 +23,12 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/v2/core/remotes"
|
||||
pusherrors "github.com/containerd/containerd/v2/core/remotes/errors"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/buildx/util/imagetools"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/specs-go"
|
||||
@@ -66,11 +67,6 @@ var clientAuthStatusCodes = []int{
|
||||
http.StatusProxyAuthRequired,
|
||||
}
|
||||
|
||||
type Pushable struct {
|
||||
Descriptor v1.Descriptor
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func DescriptorForComposeFile(path string, content []byte) v1.Descriptor {
|
||||
return v1.Descriptor{
|
||||
MediaType: ComposeYAMLMediaType,
|
||||
@@ -80,6 +76,7 @@ func DescriptorForComposeFile(path string, content []byte) v1.Descriptor {
|
||||
"com.docker.compose.version": api.ComposeVersion,
|
||||
"com.docker.compose.file": filepath.Base(path),
|
||||
},
|
||||
Data: content,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,26 +89,24 @@ func DescriptorForEnvFile(path string, content []byte) v1.Descriptor {
|
||||
"com.docker.compose.version": api.ComposeVersion,
|
||||
"com.docker.compose.envfile": filepath.Base(path),
|
||||
},
|
||||
Data: content,
|
||||
}
|
||||
}
|
||||
|
||||
func PushManifest(
|
||||
ctx context.Context,
|
||||
resolver *imagetools.Resolver,
|
||||
named reference.Named,
|
||||
layers []Pushable,
|
||||
ociVersion api.OCIVersion,
|
||||
) error {
|
||||
func PushManifest(ctx context.Context, resolver remotes.Resolver, named reference.Named, layers []v1.Descriptor, ociVersion api.OCIVersion) (v1.Descriptor, error) {
|
||||
// Check if we need an extra empty layer for the manifest config
|
||||
if ociVersion == api.OCIVersion1_1 || ociVersion == "" {
|
||||
layers = append(layers, Pushable{Descriptor: v1.DescriptorEmptyJSON, Data: []byte("{}")})
|
||||
err := push(ctx, resolver, named, v1.DescriptorEmptyJSON)
|
||||
if err != nil {
|
||||
return v1.Descriptor{}, err
|
||||
}
|
||||
}
|
||||
// prepare to push the manifest by pushing the layers
|
||||
layerDescriptors := make([]v1.Descriptor, len(layers))
|
||||
for i := range layers {
|
||||
layerDescriptors[i] = layers[i].Descriptor
|
||||
if err := resolver.Push(ctx, named, layers[i].Descriptor, layers[i].Data); err != nil {
|
||||
return err
|
||||
layerDescriptors[i] = layers[i]
|
||||
if err := push(ctx, resolver, named, layers[i]); err != nil {
|
||||
return v1.Descriptor{}, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,33 +118,36 @@ func PushManifest(
|
||||
// try to push in the OCI 1.1 format but fallback to OCI 1.0 on 4xx errors
|
||||
// (other than auth) since it's most likely the result of the registry not
|
||||
// having support
|
||||
err := createAndPushManifest(ctx, resolver, named, layerDescriptors, api.OCIVersion1_1)
|
||||
descriptor, err := createAndPushManifest(ctx, resolver, named, layerDescriptors, api.OCIVersion1_1)
|
||||
var pushErr pusherrors.ErrUnexpectedStatus
|
||||
if errors.As(err, &pushErr) && isNonAuthClientError(pushErr.StatusCode) {
|
||||
// TODO(milas): show a warning here (won't work with logrus)
|
||||
return createAndPushManifest(ctx, resolver, named, layerDescriptors, api.OCIVersion1_0)
|
||||
}
|
||||
return err
|
||||
return descriptor, err
|
||||
}
|
||||
|
||||
func createAndPushManifest(
|
||||
ctx context.Context,
|
||||
resolver *imagetools.Resolver,
|
||||
named reference.Named,
|
||||
layers []v1.Descriptor,
|
||||
ociVersion api.OCIVersion,
|
||||
) error {
|
||||
toPush, err := generateManifest(layers, ociVersion)
|
||||
func push(ctx context.Context, resolver remotes.Resolver, ref reference.Named, descriptor v1.Descriptor) error {
|
||||
fullRef, err := reference.WithDigest(reference.TagNameOnly(ref), descriptor.Digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Push(ctx, resolver, fullRef, descriptor)
|
||||
}
|
||||
|
||||
func createAndPushManifest(ctx context.Context, resolver remotes.Resolver, named reference.Named, layers []v1.Descriptor, ociVersion api.OCIVersion) (v1.Descriptor, error) {
|
||||
descriptor, toPush, err := generateManifest(layers, ociVersion)
|
||||
if err != nil {
|
||||
return v1.Descriptor{}, err
|
||||
}
|
||||
for _, p := range toPush {
|
||||
err = resolver.Push(ctx, named, p.Descriptor, p.Data)
|
||||
err = push(ctx, resolver, named, p)
|
||||
if err != nil {
|
||||
return err
|
||||
return v1.Descriptor{}, err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return descriptor, nil
|
||||
}
|
||||
|
||||
func isNonAuthClientError(statusCode int) bool {
|
||||
@@ -157,18 +155,11 @@ func isNonAuthClientError(statusCode int) bool {
|
||||
// not a client error
|
||||
return false
|
||||
}
|
||||
for _, v := range clientAuthStatusCodes {
|
||||
if statusCode == v {
|
||||
// client auth error
|
||||
return false
|
||||
}
|
||||
}
|
||||
// any other 4xx client error
|
||||
return true
|
||||
return !slices.Contains(clientAuthStatusCodes, statusCode)
|
||||
}
|
||||
|
||||
func generateManifest(layers []v1.Descriptor, ociCompat api.OCIVersion) ([]Pushable, error) {
|
||||
var toPush []Pushable
|
||||
func generateManifest(layers []v1.Descriptor, ociCompat api.OCIVersion) (v1.Descriptor, []v1.Descriptor, error) {
|
||||
var toPush []v1.Descriptor
|
||||
var config v1.Descriptor
|
||||
var artifactType string
|
||||
switch ociCompat {
|
||||
@@ -188,18 +179,18 @@ func generateManifest(layers []v1.Descriptor, ociCompat api.OCIVersion) ([]Pusha
|
||||
MediaType: ComposeEmptyConfigMediaType,
|
||||
Digest: digest.FromBytes(configData),
|
||||
Size: int64(len(configData)),
|
||||
Data: configData,
|
||||
}
|
||||
// N.B. OCI 1.0 does NOT support specifying the artifact type, so it's
|
||||
// left as an empty string to omit it from the marshaled JSON
|
||||
artifactType = ""
|
||||
toPush = append(toPush, Pushable{Descriptor: config, Data: configData})
|
||||
toPush = append(toPush, config)
|
||||
case api.OCIVersion1_1:
|
||||
config = v1.DescriptorEmptyJSON
|
||||
artifactType = ComposeProjectArtifactType
|
||||
// N.B. the descriptor has the data embedded in it
|
||||
toPush = append(toPush, Pushable{Descriptor: config, Data: make([]byte, len(config.Data))})
|
||||
toPush = append(toPush, config)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported OCI version: %s", ociCompat)
|
||||
return v1.Descriptor{}, nil, fmt.Errorf("unsupported OCI version: %s", ociCompat)
|
||||
}
|
||||
|
||||
manifest, err := json.Marshal(v1.Manifest{
|
||||
@@ -213,7 +204,7 @@ func generateManifest(layers []v1.Descriptor, ociCompat api.OCIVersion) ([]Pusha
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return v1.Descriptor{}, nil, err
|
||||
}
|
||||
|
||||
manifestDescriptor := v1.Descriptor{
|
||||
@@ -224,7 +215,8 @@ func generateManifest(layers []v1.Descriptor, ociCompat api.OCIVersion) ([]Pusha
|
||||
"com.docker.compose.version": api.ComposeVersion,
|
||||
},
|
||||
ArtifactType: artifactType,
|
||||
Data: manifest,
|
||||
}
|
||||
toPush = append(toPush, Pushable{Descriptor: manifestDescriptor, Data: manifest})
|
||||
return toPush, nil
|
||||
toPush = append(toPush, manifestDescriptor)
|
||||
return manifestDescriptor, toPush, nil
|
||||
}
|
||||
137
internal/oci/resolver.go
Normal file
137
internal/oci/resolver.go
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright 2023 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/v2/core/remotes"
|
||||
"github.com/containerd/containerd/v2/core/remotes/docker"
|
||||
"github.com/containerd/containerd/v2/pkg/labels"
|
||||
"github.com/containerd/errdefs"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/docker/compose/v2/internal/registry"
|
||||
"github.com/moby/buildkit/util/contentutil"
|
||||
spec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// NewResolver setup an OCI Resolver based on docker/cli config to provide registry credentials
|
||||
func NewResolver(config *configfile.ConfigFile) remotes.Resolver {
|
||||
return docker.NewResolver(docker.ResolverOptions{
|
||||
Hosts: docker.ConfigureDefaultRegistries(
|
||||
docker.WithAuthorizer(docker.NewDockerAuthorizer(
|
||||
docker.WithAuthCreds(func(host string) (string, string, error) {
|
||||
host = registry.GetAuthConfigKey(host)
|
||||
auth, err := config.GetAuthConfig(host)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if auth.IdentityToken != "" {
|
||||
return "", auth.IdentityToken, nil
|
||||
}
|
||||
return auth.Username, auth.Password, nil
|
||||
}),
|
||||
)),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
// Get retrieves a Named OCI resource and returns OCI Descriptor and Manifest
|
||||
func Get(ctx context.Context, resolver remotes.Resolver, ref reference.Named) (spec.Descriptor, []byte, error) {
|
||||
_, descriptor, err := resolver.Resolve(ctx, ref.String())
|
||||
if err != nil {
|
||||
return spec.Descriptor{}, nil, err
|
||||
}
|
||||
|
||||
fetcher, err := resolver.Fetcher(ctx, ref.String())
|
||||
if err != nil {
|
||||
return spec.Descriptor{}, nil, err
|
||||
}
|
||||
fetch, err := fetcher.Fetch(ctx, descriptor)
|
||||
if err != nil {
|
||||
return spec.Descriptor{}, nil, err
|
||||
}
|
||||
content, err := io.ReadAll(fetch)
|
||||
if err != nil {
|
||||
return spec.Descriptor{}, nil, err
|
||||
}
|
||||
return descriptor, content, nil
|
||||
}
|
||||
|
||||
func Copy(ctx context.Context, resolver remotes.Resolver, image reference.Named, named reference.Named) (spec.Descriptor, error) {
|
||||
src, desc, err := resolver.Resolve(ctx, image.String())
|
||||
if err != nil {
|
||||
return spec.Descriptor{}, err
|
||||
}
|
||||
if desc.Annotations == nil {
|
||||
desc.Annotations = make(map[string]string)
|
||||
}
|
||||
// set LabelDistributionSource so push will actually use a registry mount
|
||||
refspec := reference.TrimNamed(image).String()
|
||||
u, err := url.Parse("dummy://" + refspec)
|
||||
if err != nil {
|
||||
return spec.Descriptor{}, err
|
||||
}
|
||||
source, repo := u.Hostname(), strings.TrimPrefix(u.Path, "/")
|
||||
desc.Annotations[labels.LabelDistributionSource+"."+source] = repo
|
||||
|
||||
p, err := resolver.Pusher(ctx, named.Name())
|
||||
if err != nil {
|
||||
return spec.Descriptor{}, err
|
||||
}
|
||||
f, err := resolver.Fetcher(ctx, src)
|
||||
if err != nil {
|
||||
return spec.Descriptor{}, err
|
||||
}
|
||||
|
||||
err = contentutil.CopyChain(ctx,
|
||||
contentutil.FromPusher(p),
|
||||
contentutil.FromFetcher(f), desc)
|
||||
return desc, err
|
||||
}
|
||||
|
||||
func Push(ctx context.Context, resolver remotes.Resolver, ref reference.Named, descriptor spec.Descriptor) error {
|
||||
pusher, err := resolver.Pusher(ctx, ref.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx = remotes.WithMediaTypeKeyPrefix(ctx, ComposeYAMLMediaType, "artifact-")
|
||||
ctx = remotes.WithMediaTypeKeyPrefix(ctx, ComposeEnvFileMediaType, "artifact-")
|
||||
ctx = remotes.WithMediaTypeKeyPrefix(ctx, ComposeEmptyConfigMediaType, "config-")
|
||||
ctx = remotes.WithMediaTypeKeyPrefix(ctx, spec.MediaTypeEmptyJSON, "config-")
|
||||
|
||||
push, err := pusher.Push(ctx, descriptor)
|
||||
if errdefs.IsAlreadyExists(err) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = push.Write(descriptor.Data)
|
||||
if err != nil {
|
||||
// Close the writer on error since Commit won't be called
|
||||
_ = push.Close()
|
||||
return err
|
||||
}
|
||||
// Commit will close the writer
|
||||
return push.Commit(ctx, int64(len(descriptor.Data)), descriptor.Digest)
|
||||
}
|
||||
44
internal/registry/registry.go
Normal file
44
internal/registry/registry.go
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2023 Docker Compose CLI authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package registry
|
||||
|
||||
const (
|
||||
// DefaultNamespace is the default namespace
|
||||
DefaultNamespace = "docker.io"
|
||||
// DefaultRegistryHost is the hostname for the default (Docker Hub) registry
|
||||
// used for pushing and pulling images. This hostname is hard-coded to handle
|
||||
// the conversion from image references without registry name (e.g. "ubuntu",
|
||||
// or "ubuntu:latest"), as well as references using the "docker.io" domain
|
||||
// name, which is used as canonical reference for images on Docker Hub, but
|
||||
// does not match the domain-name of Docker Hub's registry.
|
||||
DefaultRegistryHost = "registry-1.docker.io"
|
||||
// IndexHostname is the index hostname, used for authentication and image search.
|
||||
IndexHostname = "index.docker.io"
|
||||
// IndexServer is used for user auth and image search
|
||||
IndexServer = "https://" + IndexHostname + "/v1/"
|
||||
// IndexName is the name of the index
|
||||
IndexName = "docker.io"
|
||||
)
|
||||
|
||||
// GetAuthConfigKey special-cases using the full index address of the official
|
||||
// index as the AuthConfig key, and uses the (host)name[:port] for private indexes.
|
||||
func GetAuthConfigKey(indexName string) string {
|
||||
if indexName == IndexName || indexName == IndexHostname || indexName == DefaultRegistryHost {
|
||||
return IndexServer
|
||||
}
|
||||
return indexName
|
||||
}
|
||||
@@ -29,11 +29,11 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/moby/go-archive"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type archiveEntry struct {
|
||||
@@ -84,7 +84,14 @@ func (t *Tar) Sync(ctx context.Context, service string, paths []*PathMapping) er
|
||||
if len(pathsToDelete) != 0 {
|
||||
deleteCmd = append([]string{"rm", "-rf"}, pathsToDelete...)
|
||||
}
|
||||
var eg multierror.Group
|
||||
|
||||
var (
|
||||
eg errgroup.Group
|
||||
errMu sync.Mutex
|
||||
errs = make([]error, 0, len(containers)*2) // max 2 errs per container
|
||||
)
|
||||
|
||||
eg.SetLimit(16) // arbitrary limit, adjust to taste :D
|
||||
for i := range containers {
|
||||
containerID := containers[i].ID
|
||||
tarReader := tarArchive(pathsToCopy)
|
||||
@@ -92,17 +99,23 @@ func (t *Tar) Sync(ctx context.Context, service string, paths []*PathMapping) er
|
||||
eg.Go(func() error {
|
||||
if len(deleteCmd) != 0 {
|
||||
if err := t.client.Exec(ctx, containerID, deleteCmd, nil); err != nil {
|
||||
return fmt.Errorf("deleting paths in %s: %w", containerID, err)
|
||||
errMu.Lock()
|
||||
errs = append(errs, fmt.Errorf("deleting paths in %s: %w", containerID, err))
|
||||
errMu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
if err := t.client.Untar(ctx, containerID, tarReader); err != nil {
|
||||
return fmt.Errorf("copying files to %s: %w", containerID, err)
|
||||
errMu.Lock()
|
||||
errs = append(errs, fmt.Errorf("copying files to %s: %w", containerID, err))
|
||||
errMu.Unlock()
|
||||
}
|
||||
return nil
|
||||
return nil // don't fail-fast; collect all errors
|
||||
})
|
||||
}
|
||||
return eg.Wait().ErrorOrNil()
|
||||
|
||||
_ = eg.Wait()
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
type ArchiveBuilder struct {
|
||||
@@ -229,7 +242,7 @@ func (a *ArchiveBuilder) writeEntry(entry archiveEntry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// tarPath writes the given source path into tarWriter at the given dest (recursively for directories).
|
||||
// entriesForPath writes the given source path into tarWriter at the given dest (recursively for directories).
|
||||
// e.g. tarring my_dir --> dest d: d/file_a, d/file_b
|
||||
// If source path does not exist, quietly skips it and returns no err
|
||||
func (a *ArchiveBuilder) entriesForPath(localPath, containerPath string) ([]archiveEntry, error) {
|
||||
|
||||
@@ -77,11 +77,13 @@ func ProjectOptions(ctx context.Context, proj *types.Project) SpanOptions {
|
||||
attribute.StringSlice("project.networks", proj.NetworkNames()),
|
||||
attribute.StringSlice("project.secrets", proj.SecretNames()),
|
||||
attribute.StringSlice("project.configs", proj.ConfigNames()),
|
||||
attribute.StringSlice("project.models", proj.ModelNames()),
|
||||
attribute.StringSlice("project.extensions", keys(proj.Extensions)),
|
||||
attribute.StringSlice("project.services.active", proj.ServiceNames()),
|
||||
attribute.StringSlice("project.services.disabled", proj.DisabledServiceNames()),
|
||||
attribute.StringSlice("project.services.build", proj.ServicesWithBuild()),
|
||||
attribute.StringSlice("project.services.depends_on", proj.ServicesWithDependsOn()),
|
||||
attribute.StringSlice("project.services.models", proj.ServicesWithModels()),
|
||||
attribute.StringSlice("project.services.capabilities", capabilities),
|
||||
attribute.StringSlice("project.services.capabilities.gpu", gpu),
|
||||
attribute.StringSlice("project.services.capabilities.tpu", tpu),
|
||||
@@ -110,6 +112,7 @@ func ServiceOptions(service types.ServiceConfig) SpanOptions {
|
||||
attribute.String("service.name", service.Name),
|
||||
attribute.String("service.image", service.Image),
|
||||
attribute.StringSlice("service.networks", keys(service.Networks)),
|
||||
attribute.StringSlice("service.models", keys(service.Models)),
|
||||
}
|
||||
|
||||
configNames := make([]string, len(service.Configs))
|
||||
|
||||
@@ -22,15 +22,12 @@ import (
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
func KeyboardMetrics(ctx context.Context, enabled, isDockerDesktopActive, isWatchConfigured bool) {
|
||||
func KeyboardMetrics(ctx context.Context, enabled, isDockerDesktopActive bool) {
|
||||
commandAvailable := []string{}
|
||||
if isDockerDesktopActive {
|
||||
commandAvailable = append(commandAvailable, "gui")
|
||||
commandAvailable = append(commandAvailable, "gui/composeview")
|
||||
}
|
||||
if isWatchConfigured {
|
||||
commandAvailable = append(commandAvailable, "watch")
|
||||
}
|
||||
|
||||
AddAttributeToSpan(ctx,
|
||||
attribute.Bool("navmenu.enabled", enabled),
|
||||
|
||||
@@ -18,8 +18,9 @@ package tracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
)
|
||||
|
||||
@@ -28,23 +29,45 @@ type MuxExporter struct {
|
||||
}
|
||||
|
||||
func (m MuxExporter) ExportSpans(ctx context.Context, spans []sdktrace.ReadOnlySpan) error {
|
||||
var eg multierror.Group
|
||||
for i := range m.exporters {
|
||||
exporter := m.exporters[i]
|
||||
eg.Go(func() error {
|
||||
return exporter.ExportSpans(ctx, spans)
|
||||
})
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
errMu sync.Mutex
|
||||
errs = make([]error, 0, len(m.exporters))
|
||||
)
|
||||
|
||||
for _, exporter := range m.exporters {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := exporter.ExportSpans(ctx, spans); err != nil {
|
||||
errMu.Lock()
|
||||
errs = append(errs, err)
|
||||
errMu.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
return eg.Wait()
|
||||
wg.Wait()
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (m MuxExporter) Shutdown(ctx context.Context) error {
|
||||
var eg multierror.Group
|
||||
for i := range m.exporters {
|
||||
exporter := m.exporters[i]
|
||||
eg.Go(func() error {
|
||||
return exporter.Shutdown(ctx)
|
||||
})
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
errMu sync.Mutex
|
||||
errs = make([]error, 0, len(m.exporters))
|
||||
)
|
||||
|
||||
for _, exporter := range m.exporters {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := exporter.Shutdown(ctx); err != nil {
|
||||
errMu.Lock()
|
||||
errs = append(errs, err)
|
||||
errMu.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
return eg.Wait()
|
||||
wg.Wait()
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
@@ -19,16 +19,20 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/cli/opts"
|
||||
"github.com/docker/compose/v2/pkg/utils"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
)
|
||||
|
||||
// Service manages a compose project
|
||||
type Service interface {
|
||||
// Compose is the API interface one can use to programmatically use docker/compose in a third-party software
|
||||
// Use [compose.NewComposeService] to get an actual instance
|
||||
type Compose interface {
|
||||
// Build executes the equivalent to a `compose build`
|
||||
Build(ctx context.Context, project *types.Project, options BuildOptions) error
|
||||
// Push executes the equivalent to a `compose push`
|
||||
@@ -78,13 +82,13 @@ type Service interface {
|
||||
// Publish executes the equivalent to a `compose publish`
|
||||
Publish(ctx context.Context, project *types.Project, repository string, options PublishOptions) error
|
||||
// Images executes the equivalent of a `compose images`
|
||||
Images(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
|
||||
Images(ctx context.Context, projectName string, options ImagesOptions) (map[string]ImageSummary, error)
|
||||
// MaxConcurrency defines upper limit for concurrent operations against engine API
|
||||
MaxConcurrency(parallel int)
|
||||
// DryRunMode defines if dry run applies to the command
|
||||
DryRunMode(ctx context.Context, dryRun bool) (context.Context, error)
|
||||
// Watch services' development context and sync/notify/rebuild/restart on changes
|
||||
Watch(ctx context.Context, project *types.Project, services []string, options WatchOptions) error
|
||||
Watch(ctx context.Context, project *types.Project, options WatchOptions) error
|
||||
// Viz generates a graphviz graph of the project services
|
||||
Viz(ctx context.Context, project *types.Project, options VizOptions) (string, error)
|
||||
// Wait blocks until at least one of the services' container exits
|
||||
@@ -97,8 +101,16 @@ type Service interface {
|
||||
Commit(ctx context.Context, projectName string, options CommitOptions) error
|
||||
// Generate generates a Compose Project from existing containers
|
||||
Generate(ctx context.Context, options GenerateOptions) (*types.Project, error)
|
||||
// Volumes executes the equivalent to a `docker volume ls`
|
||||
Volumes(ctx context.Context, project string, options VolumesOptions) ([]VolumesSummary, error)
|
||||
}
|
||||
|
||||
type VolumesOptions struct {
|
||||
Services []string
|
||||
}
|
||||
|
||||
type VolumesSummary = *volume.Volume
|
||||
|
||||
type ScaleOptions struct {
|
||||
Services []string
|
||||
}
|
||||
@@ -126,9 +138,10 @@ const WatchLogger = "#watch"
|
||||
|
||||
// WatchOptions group options of the Watch API
|
||||
type WatchOptions struct {
|
||||
Build *BuildOptions
|
||||
LogTo LogConsumer
|
||||
Prune bool
|
||||
Build *BuildOptions
|
||||
LogTo LogConsumer
|
||||
Prune bool
|
||||
Services []string
|
||||
}
|
||||
|
||||
// BuildOptions group options of the Build API
|
||||
@@ -159,8 +172,14 @@ type BuildOptions struct {
|
||||
Print bool
|
||||
// Check let builder validate build configuration
|
||||
Check bool
|
||||
// Provenance
|
||||
Provenance bool
|
||||
// Attestations allows to enable attestations generation
|
||||
Attestations bool
|
||||
// Provenance generate a provenance attestation
|
||||
Provenance string
|
||||
// SBOM generate a SBOM attestation
|
||||
SBOM string
|
||||
// Out is the stream to write build progress
|
||||
Out io.Writer
|
||||
}
|
||||
|
||||
// Apply mutates project according to build options
|
||||
@@ -175,13 +194,13 @@ func (o BuildOptions) Apply(project *types.Project) error {
|
||||
continue
|
||||
}
|
||||
if platform != "" {
|
||||
if len(service.Build.Platforms) > 0 && !utils.StringContains(service.Build.Platforms, platform) {
|
||||
if len(service.Build.Platforms) > 0 && !slices.Contains(service.Build.Platforms, platform) {
|
||||
return fmt.Errorf("service %q build.platforms does not support value set by DOCKER_DEFAULT_PLATFORM: %s", name, platform)
|
||||
}
|
||||
service.Platform = platform
|
||||
}
|
||||
if service.Platform != "" {
|
||||
if len(service.Build.Platforms) > 0 && !utils.StringContains(service.Build.Platforms, service.Platform) {
|
||||
if len(service.Build.Platforms) > 0 && !slices.Contains(service.Build.Platforms, service.Platform) {
|
||||
return fmt.Errorf("service %q build configuration does not support platform: %s", name, service.Platform)
|
||||
}
|
||||
}
|
||||
@@ -349,7 +368,7 @@ type RemoveOptions struct {
|
||||
|
||||
// RunOptions group options of the Run API
|
||||
type RunOptions struct {
|
||||
Build *BuildOptions
|
||||
CreateOptions
|
||||
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
|
||||
Project *types.Project
|
||||
Name string
|
||||
@@ -369,8 +388,6 @@ type RunOptions struct {
|
||||
Privileged bool
|
||||
UseNetworkAliases bool
|
||||
NoDeps bool
|
||||
// QuietPull makes the pulling process quiet
|
||||
QuietPull bool
|
||||
// used by exec
|
||||
Index int
|
||||
}
|
||||
@@ -389,6 +406,8 @@ type AttachOptions struct {
|
||||
type EventsOptions struct {
|
||||
Services []string
|
||||
Consumer func(event Event) error
|
||||
Since string
|
||||
Until string
|
||||
}
|
||||
|
||||
// Event is a container runtime event served by Events API
|
||||
@@ -426,9 +445,10 @@ const (
|
||||
// PublishOptions group options of the Publish API
|
||||
type PublishOptions struct {
|
||||
ResolveImageDigests bool
|
||||
Application bool
|
||||
WithEnvironment bool
|
||||
AssumeYes bool
|
||||
|
||||
AssumeYes bool
|
||||
OCIVersion OCIVersion
|
||||
}
|
||||
|
||||
@@ -535,12 +555,13 @@ type ContainerProcSummary struct {
|
||||
|
||||
// ImageSummary holds container image description
|
||||
type ImageSummary struct {
|
||||
ID string
|
||||
ContainerName string
|
||||
Repository string
|
||||
Tag string
|
||||
Size int64
|
||||
LastTagTime time.Time
|
||||
ID string
|
||||
Repository string
|
||||
Tag string
|
||||
Platform platforms.Platform
|
||||
Size int64
|
||||
Created time.Time
|
||||
LastTagTime time.Time
|
||||
}
|
||||
|
||||
// ServiceStatus hold status about a service
|
||||
@@ -638,7 +659,6 @@ type LogConsumer interface {
|
||||
Log(containerName, message string)
|
||||
Err(containerName, message string)
|
||||
Status(container, msg string)
|
||||
Register(container string)
|
||||
}
|
||||
|
||||
// ContainerEventListener is a callback to process ContainerEvent from services
|
||||
@@ -646,16 +666,18 @@ type ContainerEventListener func(event ContainerEvent)
|
||||
|
||||
// ContainerEvent notify an event has been collected on source container implementing Service
|
||||
type ContainerEvent struct {
|
||||
Type int
|
||||
// Container is the name of the container _without the project prefix_.
|
||||
Type int
|
||||
Time int64
|
||||
Container *ContainerSummary
|
||||
// Source is the name of the container _without the project prefix_.
|
||||
//
|
||||
// This is only suitable for display purposes within Compose, as it's
|
||||
// not guaranteed to be unique across services.
|
||||
Container string
|
||||
ID string
|
||||
Service string
|
||||
Line string
|
||||
// ContainerEventExit only
|
||||
Source string
|
||||
ID string
|
||||
Service string
|
||||
Line string
|
||||
// ExitCode is only set on ContainerEventExited events
|
||||
ExitCode int
|
||||
Restarting bool
|
||||
}
|
||||
@@ -665,17 +687,19 @@ const (
|
||||
ContainerEventLog = iota
|
||||
// ContainerEventErr is a ContainerEvent of type log on stderr. Line is set
|
||||
ContainerEventErr
|
||||
// ContainerEventAttach is a ContainerEvent of type attach. First event sent about a container
|
||||
ContainerEventAttach
|
||||
// ContainerEventStarted let consumer know a container has been started
|
||||
ContainerEventStarted
|
||||
// ContainerEventRestarted let consumer know a container has been restarted
|
||||
ContainerEventRestarted
|
||||
// ContainerEventStopped is a ContainerEvent of type stopped.
|
||||
ContainerEventStopped
|
||||
// ContainerEventCreated let consumer know a new container has been created
|
||||
ContainerEventCreated
|
||||
// ContainerEventRecreated let consumer know container stopped but his being replaced
|
||||
ContainerEventRecreated
|
||||
// ContainerEventExit is a ContainerEvent of type exit. ExitCode is set
|
||||
ContainerEventExit
|
||||
// ContainerEventExited is a ContainerEvent of type exit. ExitCode is set
|
||||
ContainerEventExited
|
||||
// UserCancel user cancelled compose up, we are stopping containers
|
||||
UserCancel
|
||||
// HookEventLog is a ContainerEvent of type log on stdout by service hook
|
||||
HookEventLog
|
||||
)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user