WIP fix: Allows multiple protocols on one port #741
4
go.mod
4
go.mod
@ -13,7 +13,7 @@ require (
|
||||
github.com/charmbracelet/log v0.4.2
|
||||
github.com/distribution/reference v0.6.0
|
||||
github.com/docker/cli v28.4.0+incompatible
|
||||
github.com/docker/docker v28.4.0+incompatible
|
||||
github.com/docker/docker v28.5.2+incompatible
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/go-git/go-git/v5 v5.16.2
|
||||
github.com/google/go-cmp v0.7.0
|
||||
@ -157,3 +157,5 @@ require (
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
golang.org/x/sys v0.36.0
|
||||
)
|
||||
|
||||
replace github.com/docker/cli v28.4.0+incompatible => git.coopcloud.tech/p4u1/docker-cli v28.5.3-0.20260202112816-30df2d0b3a00+incompatible
|
||||
|
||||
8
go.sum
8
go.sum
@ -27,6 +27,8 @@ coopcloud.tech/tagcmp v0.0.0-20250818180036-0ec1b205b5ca/go.mod h1:ESVm0wQKcbcFi
|
||||
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
git.coopcloud.tech/p4u1/docker-cli v28.5.3-0.20260202112816-30df2d0b3a00+incompatible h1:K4a+GLDBHiQdacGLWsxkiiVU9cU5bxzc2FQfYtu6Tuw=
|
||||
git.coopcloud.tech/p4u1/docker-cli v28.5.3-0.20260202112816-30df2d0b3a00+incompatible/go.mod h1:erotfvNdiML+bok5L5wN/fQk9/tNcK21O2/6vug05kE=
|
||||
git.coopcloud.tech/toolshed/godotenv v1.5.2-0.20250103171850-4d0ca41daa5c h1:oeKnUB79PKYD8D0/unYuu7MRcWryQQWOns8+JL+acrs=
|
||||
git.coopcloud.tech/toolshed/godotenv v1.5.2-0.20250103171850-4d0ca41daa5c/go.mod h1:fQuhwrpg6qb9NlFXKYi/LysWu1wxjraS8sxyW12CUF0=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||
@ -318,16 +320,14 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v28.4.0+incompatible h1:RBcf3Kjw2pMtwui5V0DIMdyeab8glEw5QY0UUU4C9kY=
|
||||
github.com/docker/cli v28.4.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v28.4.0+incompatible h1:KVC7bz5zJY/4AZe/78BIvCnPsLaC9T/zh72xnlrTTOk=
|
||||
github.com/docker/docker v28.4.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
|
||||
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
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=
|
||||
|
||||
@ -602,3 +602,24 @@ teardown(){
|
||||
refute_output --partial "WITH_COMMENT=foo"
|
||||
assert_output --partial "WITH_COMMENT=bar"
|
||||
}
|
||||
|
||||
# bats test_tags=slow
|
||||
@test "deploy with udp and tcp on same port" {
|
||||
run sed -i 's/TYPE=abra-test-recipe:.*/TYPE=git.coopcloud.tech\/p4u1\/abra-test-recipe:030e8a1cb1a0f17281847b3e55d829220ad32c50/g' \
|
||||
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||
assert_success
|
||||
|
||||
# run sed -i 's/#COMPOSE_FILE="$COMPOSE_FILE:compose.udp-and-tcp.yml"/COMPOSE_FILE="$COMPOSE_FILE:compose.udp-and-tcp.yml"/g' \
|
||||
# "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||
run bash -c "printf '\nCOMPOSE_FILE=\"\$COMPOSE_FILE:compose.udp-and-tcp.yml\"' >> $ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||
assert_success
|
||||
|
||||
run $ABRA app deploy "$TEST_APP_DOMAIN" --no-input
|
||||
assert_success
|
||||
|
||||
run docker service inspect --format '{{ range .Endpoint.Ports }}{{ .Protocol }}={{ .PublishedPort }}{{ end }}' \
|
||||
"${TEST_APP_DOMAIN//./_}_app"
|
||||
assert_success
|
||||
assert_output --partial "tcp=1312"
|
||||
assert_output --partial "udp=1312"
|
||||
}
|
||||
|
||||
2
vendor/github.com/docker/cli/cli-plugins/metadata/metadata.go
generated
vendored
2
vendor/github.com/docker/cli/cli-plugins/metadata/metadata.go
generated
vendored
@ -33,4 +33,6 @@ type Metadata struct {
|
||||
ShortDescription string `json:",omitempty"`
|
||||
// URL is a pointer to the plugin's homepage.
|
||||
URL string `json:",omitempty"`
|
||||
// Hidden hides the plugin in completion and help message output.
|
||||
Hidden bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
7
vendor/github.com/docker/cli/cli/cobra.go
generated
vendored
7
vendor/github.com/docker/cli/cli/cobra.go
generated
vendored
@ -376,13 +376,10 @@ func orchestratorSubCommands(cmd *cobra.Command) []*cobra.Command {
|
||||
func allManagementSubCommands(cmd *cobra.Command) []*cobra.Command {
|
||||
cmds := []*cobra.Command{}
|
||||
for _, sub := range cmd.Commands() {
|
||||
if isPlugin(sub) {
|
||||
if invalidPluginReason(sub) == "" {
|
||||
cmds = append(cmds, sub)
|
||||
}
|
||||
if invalidPluginReason(sub) != "" {
|
||||
continue
|
||||
}
|
||||
if sub.IsAvailableCommand() && sub.HasSubCommands() {
|
||||
if sub.IsAvailableCommand() && (isPlugin(sub) || sub.HasSubCommands()) {
|
||||
cmds = append(cmds, sub)
|
||||
}
|
||||
}
|
||||
|
||||
40
vendor/github.com/docker/cli/cli/command/cli.go
generated
vendored
40
vendor/github.com/docker/cli/cli/command/cli.go
generated
vendored
@ -48,9 +48,7 @@ type Cli interface {
|
||||
Apply(ops ...CLIOption) error
|
||||
config.Provider
|
||||
ServerInfo() ServerInfo
|
||||
DefaultVersion() string
|
||||
CurrentVersion() string
|
||||
ContentTrustEnabled() bool
|
||||
BuildKitEnabled() (bool, error)
|
||||
ContextStore() store.Store
|
||||
CurrentContext() string
|
||||
@ -78,6 +76,7 @@ type DockerCli struct {
|
||||
dockerEndpoint docker.Endpoint
|
||||
contextStoreConfig *store.Config
|
||||
initTimeout time.Duration
|
||||
userAgent string
|
||||
res telemetryResource
|
||||
|
||||
// baseCtx is the base context used for internal operations. In the future
|
||||
@ -89,6 +88,8 @@ type DockerCli struct {
|
||||
}
|
||||
|
||||
// DefaultVersion returns [api.DefaultVersion].
|
||||
//
|
||||
// Deprecated: this function is no longer used and will be removed in the next release.
|
||||
func (*DockerCli) DefaultVersion() string {
|
||||
return api.DefaultVersion
|
||||
}
|
||||
@ -159,6 +160,8 @@ func (cli *DockerCli) ServerInfo() ServerInfo {
|
||||
|
||||
// ContentTrustEnabled returns whether content trust has been enabled by an
|
||||
// environment variable.
|
||||
//
|
||||
// Deprecated: check the value of the DOCKER_CONTENT_TRUST environment variable to detect whether content-trust is enabled.
|
||||
func (cli *DockerCli) ContentTrustEnabled() bool {
|
||||
return cli.contentTrust
|
||||
}
|
||||
@ -269,7 +272,7 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption)
|
||||
cli.contextStore = &ContextStoreWithDefault{
|
||||
Store: store.New(config.ContextStoreDir(), *cli.contextStoreConfig),
|
||||
Resolver: func() (*DefaultContext, error) {
|
||||
return ResolveDefaultContext(cli.options, *cli.contextStoreConfig)
|
||||
return resolveDefaultContext(cli.options, *cli.contextStoreConfig)
|
||||
},
|
||||
}
|
||||
|
||||
@ -306,17 +309,17 @@ func NewAPIClientFromFlags(opts *cliflags.ClientOptions, configFile *configfile.
|
||||
contextStore := &ContextStoreWithDefault{
|
||||
Store: store.New(config.ContextStoreDir(), storeConfig),
|
||||
Resolver: func() (*DefaultContext, error) {
|
||||
return ResolveDefaultContext(opts, storeConfig)
|
||||
return resolveDefaultContext(opts, storeConfig)
|
||||
},
|
||||
}
|
||||
endpoint, err := resolveDockerEndpoint(contextStore, resolveContextName(opts, configFile))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to resolve docker endpoint")
|
||||
}
|
||||
return newAPIClientFromEndpoint(endpoint, configFile)
|
||||
return newAPIClientFromEndpoint(endpoint, configFile, client.WithUserAgent(UserAgent()))
|
||||
}
|
||||
|
||||
func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigFile) (client.APIClient, error) {
|
||||
func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigFile, extraOpts ...client.Opt) (client.APIClient, error) {
|
||||
opts, err := ep.ClientOpts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -324,7 +327,14 @@ func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigF
|
||||
if len(configFile.HTTPHeaders) > 0 {
|
||||
opts = append(opts, client.WithHTTPHeaders(configFile.HTTPHeaders))
|
||||
}
|
||||
opts = append(opts, withCustomHeadersFromEnv(), client.WithUserAgent(UserAgent()))
|
||||
withCustomHeaders, err := withCustomHeadersFromEnv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if withCustomHeaders != nil {
|
||||
opts = append(opts, withCustomHeaders)
|
||||
}
|
||||
opts = append(opts, extraOpts...)
|
||||
return client.NewClientWithOpts(opts...)
|
||||
}
|
||||
|
||||
@ -545,7 +555,8 @@ func (cli *DockerCli) initialize() error {
|
||||
return
|
||||
}
|
||||
if cli.client == nil {
|
||||
if cli.client, cli.initErr = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile); cli.initErr != nil {
|
||||
ops := []client.Opt{client.WithUserAgent(cli.userAgent)}
|
||||
if cli.client, cli.initErr = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile, ops...); cli.initErr != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -558,6 +569,8 @@ func (cli *DockerCli) initialize() error {
|
||||
}
|
||||
|
||||
// Apply all the operation on the cli
|
||||
//
|
||||
// Deprecated: this method is no longer used and will be removed in the next release if there are no remaining users.
|
||||
func (cli *DockerCli) Apply(ops ...CLIOption) error {
|
||||
for _, op := range ops {
|
||||
if err := op(cli); err != nil {
|
||||
@ -589,15 +602,18 @@ type ServerInfo struct {
|
||||
// environment.
|
||||
func NewDockerCli(ops ...CLIOption) (*DockerCli, error) {
|
||||
defaultOps := []CLIOption{
|
||||
WithContentTrustFromEnv(),
|
||||
withContentTrustFromEnv(),
|
||||
WithDefaultContextStoreConfig(),
|
||||
WithStandardStreams(),
|
||||
WithUserAgent(UserAgent()),
|
||||
}
|
||||
ops = append(defaultOps, ops...)
|
||||
|
||||
cli := &DockerCli{baseCtx: context.Background()}
|
||||
if err := cli.Apply(ops...); err != nil {
|
||||
return nil, err
|
||||
for _, op := range ops {
|
||||
if err := op(cli); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return cli, nil
|
||||
}
|
||||
@ -613,7 +629,7 @@ func getServerHost(hosts []string, defaultToTLS bool) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// UserAgent returns the user agent string used for making API requests
|
||||
// UserAgent returns the default user agent string used for making API requests.
|
||||
func UserAgent() string {
|
||||
return "Docker-Client/" + version.Version + " (" + runtime.GOOS + ")"
|
||||
}
|
||||
|
||||
118
vendor/github.com/docker/cli/cli/command/cli_options.go
generated
vendored
118
vendor/github.com/docker/cli/cli/command/cli_options.go
generated
vendored
@ -75,8 +75,8 @@ func WithErrorStream(err io.Writer) CLIOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithContentTrustFromEnv enables content trust on a cli from environment variable DOCKER_CONTENT_TRUST value.
|
||||
func WithContentTrustFromEnv() CLIOption {
|
||||
// withContentTrustFromEnv enables content trust on a cli from environment variable DOCKER_CONTENT_TRUST value.
|
||||
func withContentTrustFromEnv() CLIOption {
|
||||
return func(cli *DockerCli) error {
|
||||
cli.contentTrust = false
|
||||
if e := os.Getenv("DOCKER_CONTENT_TRUST"); e != "" {
|
||||
@ -89,7 +89,16 @@ func WithContentTrustFromEnv() CLIOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithContentTrustFromEnv enables content trust on a cli from environment variable DOCKER_CONTENT_TRUST value.
|
||||
//
|
||||
// Deprecated: this option is no longer used, and will be removed in the next release.
|
||||
func WithContentTrustFromEnv() CLIOption {
|
||||
return withContentTrustFromEnv()
|
||||
}
|
||||
|
||||
// WithContentTrust enables content trust on a cli.
|
||||
//
|
||||
// Deprecated: this option is no longer used, and will be removed in the next release.
|
||||
func WithContentTrust(enabled bool) CLIOption {
|
||||
return func(cli *DockerCli) error {
|
||||
cli.contentTrust = enabled
|
||||
@ -180,61 +189,70 @@ const envOverrideHTTPHeaders = "DOCKER_CUSTOM_HEADERS"
|
||||
// override headers with the same name).
|
||||
//
|
||||
// TODO(thaJeztah): this is a client Option, and should be moved to the client. It is non-exported for that reason.
|
||||
func withCustomHeadersFromEnv() client.Opt {
|
||||
return func(apiClient *client.Client) error {
|
||||
value := os.Getenv(envOverrideHTTPHeaders)
|
||||
if value == "" {
|
||||
return nil
|
||||
}
|
||||
csvReader := csv.NewReader(strings.NewReader(value))
|
||||
fields, err := csvReader.Read()
|
||||
if err != nil {
|
||||
return invalidParameter(errors.Errorf(
|
||||
"failed to parse custom headers from %s environment variable: value must be formatted as comma-separated key=value pairs",
|
||||
envOverrideHTTPHeaders,
|
||||
func withCustomHeadersFromEnv() (client.Opt, error) {
|
||||
value := os.Getenv(envOverrideHTTPHeaders)
|
||||
if value == "" {
|
||||
return nil, nil
|
||||
}
|
||||
csvReader := csv.NewReader(strings.NewReader(value))
|
||||
fields, err := csvReader.Read()
|
||||
if err != nil {
|
||||
return nil, invalidParameter(errors.Errorf(
|
||||
"failed to parse custom headers from %s environment variable: value must be formatted as comma-separated key=value pairs",
|
||||
envOverrideHTTPHeaders,
|
||||
))
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
env := map[string]string{}
|
||||
for _, kv := range fields {
|
||||
k, v, hasValue := strings.Cut(kv, "=")
|
||||
|
||||
// Only strip whitespace in keys; preserve whitespace in values.
|
||||
k = strings.TrimSpace(k)
|
||||
|
||||
if k == "" {
|
||||
return nil, invalidParameter(errors.Errorf(
|
||||
`failed to set custom headers from %s environment variable: value contains a key=value pair with an empty key: '%s'`,
|
||||
envOverrideHTTPHeaders, kv,
|
||||
))
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
return nil
|
||||
|
||||
// We don't currently allow empty key=value pairs, and produce an error.
|
||||
// This is something we could allow in future (e.g. to read value
|
||||
// from an environment variable with the same name). In the meantime,
|
||||
// produce an error to prevent users from depending on this.
|
||||
if !hasValue {
|
||||
return nil, invalidParameter(errors.Errorf(
|
||||
`failed to set custom headers from %s environment variable: missing "=" in key=value pair: '%s'`,
|
||||
envOverrideHTTPHeaders, kv,
|
||||
))
|
||||
}
|
||||
|
||||
env := map[string]string{}
|
||||
for _, kv := range fields {
|
||||
k, v, hasValue := strings.Cut(kv, "=")
|
||||
env[http.CanonicalHeaderKey(k)] = v
|
||||
}
|
||||
|
||||
// Only strip whitespace in keys; preserve whitespace in values.
|
||||
k = strings.TrimSpace(k)
|
||||
if len(env) == 0 {
|
||||
// We should probably not hit this case, as we don't skip values
|
||||
// (only return errors), but we don't want to discard existing
|
||||
// headers with an empty set.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if k == "" {
|
||||
return invalidParameter(errors.Errorf(
|
||||
`failed to set custom headers from %s environment variable: value contains a key=value pair with an empty key: '%s'`,
|
||||
envOverrideHTTPHeaders, kv,
|
||||
))
|
||||
}
|
||||
// TODO(thaJeztah): add a client.WithExtraHTTPHeaders() function to allow these headers to be _added_ to existing ones, instead of _replacing_
|
||||
// see https://github.com/docker/cli/pull/5098#issuecomment-2147403871 (when updating, also update the WARNING in the function and env-var GoDoc)
|
||||
return client.WithHTTPHeaders(env), nil
|
||||
}
|
||||
|
||||
// We don't currently allow empty key=value pairs, and produce an error.
|
||||
// This is something we could allow in future (e.g. to read value
|
||||
// from an environment variable with the same name). In the meantime,
|
||||
// produce an error to prevent users from depending on this.
|
||||
if !hasValue {
|
||||
return invalidParameter(errors.Errorf(
|
||||
`failed to set custom headers from %s environment variable: missing "=" in key=value pair: '%s'`,
|
||||
envOverrideHTTPHeaders, kv,
|
||||
))
|
||||
}
|
||||
|
||||
env[http.CanonicalHeaderKey(k)] = v
|
||||
// WithUserAgent configures the User-Agent string for cli HTTP requests.
|
||||
func WithUserAgent(userAgent string) CLIOption {
|
||||
return func(cli *DockerCli) error {
|
||||
if userAgent == "" {
|
||||
return errors.New("user agent cannot be blank")
|
||||
}
|
||||
|
||||
if len(env) == 0 {
|
||||
// We should probably not hit this case, as we don't skip values
|
||||
// (only return errors), but we don't want to discard existing
|
||||
// headers with an empty set.
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(thaJeztah): add a client.WithExtraHTTPHeaders() function to allow these headers to be _added_ to existing ones, instead of _replacing_
|
||||
// see https://github.com/docker/cli/pull/5098#issuecomment-2147403871 (when updating, also update the WARNING in the function and env-var GoDoc)
|
||||
return client.WithHTTPHeaders(env)(apiClient)
|
||||
cli.userAgent = userAgent
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
7
vendor/github.com/docker/cli/cli/command/defaultcontextstore.go
generated
vendored
7
vendor/github.com/docker/cli/cli/command/defaultcontextstore.go
generated
vendored
@ -52,7 +52,14 @@ type EndpointDefaultResolver interface {
|
||||
}
|
||||
|
||||
// ResolveDefaultContext creates a Metadata for the current CLI invocation parameters
|
||||
//
|
||||
// Deprecated: this function is exported for testing and meant for internal use. It will be removed in the next release.
|
||||
func ResolveDefaultContext(opts *cliflags.ClientOptions, config store.Config) (*DefaultContext, error) {
|
||||
return resolveDefaultContext(opts, config)
|
||||
}
|
||||
|
||||
// resolveDefaultContext creates a Metadata for the current CLI invocation parameters
|
||||
func resolveDefaultContext(opts *cliflags.ClientOptions, config store.Config) (*DefaultContext, error) {
|
||||
contextTLSData := store.ContextTLSData{
|
||||
Endpoints: make(map[string]store.EndpointTLSData),
|
||||
}
|
||||
|
||||
2
vendor/github.com/docker/cli/cli/command/formatter/tabwriter/tabwriter.go
generated
vendored
2
vendor/github.com/docker/cli/cli/command/formatter/tabwriter/tabwriter.go
generated
vendored
@ -12,7 +12,7 @@
|
||||
|
||||
// based on https://github.com/golang/go/blob/master/src/text/tabwriter/tabwriter.go Last modified 690ac40 on 31 Jan
|
||||
|
||||
//nolint:gocyclo,nakedret,unused // ignore linting errors, so that we can stick close to upstream
|
||||
//nolint:gocyclo,gofumpt,nakedret,unused // ignore linting errors, so that we can stick close to upstream
|
||||
package tabwriter
|
||||
|
||||
import (
|
||||
|
||||
40
vendor/github.com/docker/cli/cli/command/registry.go
generated
vendored
40
vendor/github.com/docker/cli/cli/command/registry.go
generated
vendored
@ -77,7 +77,16 @@ func ResolveAuthConfig(cfg *configfile.ConfigFile, index *registrytypes.IndexInf
|
||||
}
|
||||
|
||||
a, _ := cfg.GetAuthConfig(configKey)
|
||||
return registrytypes.AuthConfig(a)
|
||||
return registrytypes.AuthConfig{
|
||||
Username: a.Username,
|
||||
Password: a.Password,
|
||||
ServerAddress: a.ServerAddress,
|
||||
|
||||
// TODO(thaJeztah): Are these expected to be included?
|
||||
Auth: a.Auth,
|
||||
IdentityToken: a.IdentityToken,
|
||||
RegistryToken: a.RegistryToken,
|
||||
}
|
||||
}
|
||||
|
||||
// GetDefaultAuthConfig gets the default auth config given a serverAddress
|
||||
@ -86,19 +95,27 @@ func GetDefaultAuthConfig(cfg *configfile.ConfigFile, checkCredStore bool, serve
|
||||
if !isDefaultRegistry {
|
||||
serverAddress = credentials.ConvertToHostname(serverAddress)
|
||||
}
|
||||
authconfig := configtypes.AuthConfig{}
|
||||
authCfg := configtypes.AuthConfig{}
|
||||
var err error
|
||||
if checkCredStore {
|
||||
authconfig, err = cfg.GetAuthConfig(serverAddress)
|
||||
authCfg, err = cfg.GetAuthConfig(serverAddress)
|
||||
if err != nil {
|
||||
return registrytypes.AuthConfig{
|
||||
ServerAddress: serverAddress,
|
||||
}, err
|
||||
}
|
||||
}
|
||||
authconfig.ServerAddress = serverAddress
|
||||
authconfig.IdentityToken = ""
|
||||
return registrytypes.AuthConfig(authconfig), nil
|
||||
|
||||
return registrytypes.AuthConfig{
|
||||
Username: authCfg.Username,
|
||||
Password: authCfg.Password,
|
||||
ServerAddress: serverAddress,
|
||||
|
||||
// TODO(thaJeztah): Are these expected to be included?
|
||||
Auth: authCfg.Auth,
|
||||
IdentityToken: "",
|
||||
RegistryToken: authCfg.RegistryToken,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PromptUserForCredentials handles the CLI prompt for the user to input
|
||||
@ -213,7 +230,16 @@ func RetrieveAuthTokenFromImage(cfg *configfile.ConfigFile, image string) (strin
|
||||
return "", err
|
||||
}
|
||||
|
||||
encodedAuth, err := registrytypes.EncodeAuthConfig(registrytypes.AuthConfig(authConfig))
|
||||
encodedAuth, err := registrytypes.EncodeAuthConfig(registrytypes.AuthConfig{
|
||||
Username: authConfig.Username,
|
||||
Password: authConfig.Password,
|
||||
ServerAddress: authConfig.ServerAddress,
|
||||
|
||||
// TODO(thaJeztah): Are these expected to be included?
|
||||
Auth: authConfig.Auth,
|
||||
IdentityToken: authConfig.IdentityToken,
|
||||
RegistryToken: authConfig.RegistryToken,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
7
vendor/github.com/docker/cli/cli/compose/loader/merge.go
generated
vendored
7
vendor/github.com/docker/cli/cli/compose/loader/merge.go
generated
vendored
@ -4,6 +4,7 @@
|
||||
package loader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
@ -116,7 +117,11 @@ func toServicePortConfigsMap(s any) (map[any]any, error) {
|
||||
}
|
||||
m := map[any]any{}
|
||||
for _, p := range ports {
|
||||
m[p.Published] = p
|
||||
protocol := "tcp"
|
||||
if p.Protocol != "" {
|
||||
protocol = p.Protocol
|
||||
}
|
||||
m[fmt.Sprintf("%d%s", p.Published, protocol)] = p
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
12
vendor/github.com/docker/cli/cli/config/memorystore/store.go
generated
vendored
12
vendor/github.com/docker/cli/cli/config/memorystore/store.go
generated
vendored
@ -3,7 +3,6 @@
|
||||
package memorystore
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
@ -13,12 +12,17 @@ import (
|
||||
"github.com/docker/cli/cli/config/types"
|
||||
)
|
||||
|
||||
var errValueNotFound = errors.New("value not found")
|
||||
// notFoundErr is the error returned when a plugin could not be found.
|
||||
type notFoundErr string
|
||||
|
||||
func IsErrValueNotFound(err error) bool {
|
||||
return errors.Is(err, errValueNotFound)
|
||||
func (notFoundErr) NotFound() {}
|
||||
|
||||
func (e notFoundErr) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
var errValueNotFound notFoundErr = "value not found"
|
||||
|
||||
type Config struct {
|
||||
lock sync.RWMutex
|
||||
memoryCredentials map[string]types.AuthConfig
|
||||
|
||||
36
vendor/github.com/docker/cli/cli/context/docker/load.go
generated
vendored
36
vendor/github.com/docker/cli/cli/context/docker/load.go
generated
vendored
@ -101,7 +101,22 @@ func (ep *Endpoint) ClientOpts() ([]client.Opt, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, withHTTPClient(tlsConfig))
|
||||
|
||||
// If there's no tlsConfig available, we use the default HTTPClient.
|
||||
if tlsConfig != nil {
|
||||
result = append(result,
|
||||
client.WithHTTPClient(&http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
DialContext: (&net.Dialer{
|
||||
KeepAlive: 30 * time.Second,
|
||||
Timeout: 30 * time.Second,
|
||||
}).DialContext,
|
||||
},
|
||||
CheckRedirect: client.CheckRedirect,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
result = append(result, client.WithHost(ep.Host))
|
||||
} else {
|
||||
@ -133,25 +148,6 @@ func isSocket(addr string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func withHTTPClient(tlsConfig *tls.Config) func(*client.Client) error {
|
||||
return func(c *client.Client) error {
|
||||
if tlsConfig == nil {
|
||||
// Use the default HTTPClient
|
||||
return nil
|
||||
}
|
||||
return client.WithHTTPClient(&http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
DialContext: (&net.Dialer{
|
||||
KeepAlive: 30 * time.Second,
|
||||
Timeout: 30 * time.Second,
|
||||
}).DialContext,
|
||||
},
|
||||
CheckRedirect: client.CheckRedirect,
|
||||
})(c)
|
||||
}
|
||||
}
|
||||
|
||||
// EndpointFromContext parses a context docker endpoint metadata into a typed EndpointMeta structure
|
||||
func EndpointFromContext(metadata store.Metadata) (EndpointMeta, error) {
|
||||
ep, ok := metadata.Endpoints[DockerEndpoint]
|
||||
|
||||
4
vendor/github.com/docker/cli/opts/opts.go
generated
vendored
4
vendor/github.com/docker/cli/opts/opts.go
generated
vendored
@ -60,6 +60,8 @@ func (opts *ListOpts) Set(value string) error {
|
||||
}
|
||||
|
||||
// Delete removes the specified element from the slice.
|
||||
//
|
||||
// Deprecated: this method is no longer used and will be removed in the next release.
|
||||
func (opts *ListOpts) Delete(key string) {
|
||||
for i, k := range *opts.values {
|
||||
if k == key {
|
||||
@ -264,6 +266,8 @@ func ValidateIPAddress(val string) (string, error) {
|
||||
}
|
||||
|
||||
// ValidateMACAddress validates a MAC address.
|
||||
//
|
||||
// Deprecated: use [net.ParseMAC]. This function will be removed in the next release.
|
||||
func ValidateMACAddress(val string) (string, error) {
|
||||
_, err := net.ParseMAC(strings.TrimSpace(val))
|
||||
if err != nil {
|
||||
|
||||
6
vendor/github.com/docker/cli/templates/templates.go
generated
vendored
6
vendor/github.com/docker/cli/templates/templates.go
generated
vendored
@ -71,7 +71,7 @@ var HeaderFunctions = template.FuncMap{
|
||||
// Parse creates a new anonymous template with the basic functions
|
||||
// and parses the given format.
|
||||
func Parse(format string) (*template.Template, error) {
|
||||
return NewParse("", format)
|
||||
return template.New("").Funcs(basicFunctions).Parse(format)
|
||||
}
|
||||
|
||||
// New creates a new empty template with the provided tag and built-in
|
||||
@ -82,8 +82,10 @@ func New(tag string) *template.Template {
|
||||
|
||||
// NewParse creates a new tagged template with the basic functions
|
||||
// and parses the given format.
|
||||
//
|
||||
// Deprecated: this function is unused and will be removed in the next release. Use [New] if you need to set a tag, or [Parse] instead.
|
||||
func NewParse(tag, format string) (*template.Template, error) {
|
||||
return New(tag).Parse(format)
|
||||
return template.New(tag).Funcs(basicFunctions).Parse(format)
|
||||
}
|
||||
|
||||
// padWithSpace adds whitespace to the input if the input is non-empty
|
||||
|
||||
103
vendor/github.com/docker/docker/api/swagger.yaml
generated
vendored
103
vendor/github.com/docker/docker/api/swagger.yaml
generated
vendored
@ -81,7 +81,6 @@ info:
|
||||
{
|
||||
"username": "string",
|
||||
"password": "string",
|
||||
"email": "string",
|
||||
"serveraddress": "string"
|
||||
}
|
||||
```
|
||||
@ -637,6 +636,9 @@ definitions:
|
||||
by the default (runc) runtime.
|
||||
|
||||
This field is omitted when empty.
|
||||
|
||||
**Deprecated**: This field is deprecated as kernel 6.12 has deprecated `memory.kmem.tcp.limit_in_bytes` field
|
||||
for cgroups v1. This field will be removed in a future release.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
MemoryReservation:
|
||||
@ -1531,37 +1533,6 @@ definitions:
|
||||
items:
|
||||
type: "string"
|
||||
example: ["/bin/sh", "-c"]
|
||||
# FIXME(thaJeztah): temporarily using a full example to remove some "omitempty" fields. Remove once the fields are removed.
|
||||
example:
|
||||
"User": "web:web"
|
||||
"ExposedPorts": {
|
||||
"80/tcp": {},
|
||||
"443/tcp": {}
|
||||
}
|
||||
"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]
|
||||
"Cmd": ["/bin/sh"]
|
||||
"Healthcheck": {
|
||||
"Test": ["string"],
|
||||
"Interval": 0,
|
||||
"Timeout": 0,
|
||||
"Retries": 0,
|
||||
"StartPeriod": 0,
|
||||
"StartInterval": 0
|
||||
}
|
||||
"ArgsEscaped": true
|
||||
"Volumes": {
|
||||
"/app/data": {},
|
||||
"/app/config": {}
|
||||
}
|
||||
"WorkingDir": "/public/"
|
||||
"Entrypoint": []
|
||||
"OnBuild": []
|
||||
"Labels": {
|
||||
"com.example.some-label": "some-value",
|
||||
"com.example.some-other-label": "some-other-value"
|
||||
}
|
||||
"StopSignal": "SIGTERM"
|
||||
"Shell": ["/bin/sh", "-c"]
|
||||
|
||||
NetworkingConfig:
|
||||
description: |
|
||||
@ -1967,6 +1938,11 @@ definitions:
|
||||
Depending on how the image was created, this field may be empty and
|
||||
is only set for images that were built/created locally. This field
|
||||
is empty if the image was pulled from an image registry.
|
||||
|
||||
> **Deprecated**: This field is only set when using the deprecated
|
||||
> legacy builder. It is included in API responses for informational
|
||||
> purposes, but should not be depended on as it will be omitted
|
||||
> once the legacy builder is removed.
|
||||
type: "string"
|
||||
x-nullable: false
|
||||
example: ""
|
||||
@ -1992,6 +1968,11 @@ definitions:
|
||||
The version of Docker that was used to build the image.
|
||||
|
||||
Depending on how the image was created, this field may be empty.
|
||||
|
||||
> **Deprecated**: This field is only set when using the deprecated
|
||||
> legacy builder. It is included in API responses for informational
|
||||
> purposes, but should not be depended on as it will be omitted
|
||||
> once the legacy builder is removed.
|
||||
type: "string"
|
||||
x-nullable: false
|
||||
example: "27.0.1"
|
||||
@ -2036,14 +2017,6 @@ definitions:
|
||||
format: "int64"
|
||||
x-nullable: false
|
||||
example: 1239828
|
||||
VirtualSize:
|
||||
description: |
|
||||
Total size of the image including all layers it is composed of.
|
||||
|
||||
Deprecated: this field is omitted in API v1.44, but kept for backward compatibility. Use Size instead.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
example: 1239828
|
||||
GraphDriver:
|
||||
$ref: "#/definitions/DriverData"
|
||||
RootFS:
|
||||
@ -2176,14 +2149,6 @@ definitions:
|
||||
format: "int64"
|
||||
x-nullable: false
|
||||
example: 1239828
|
||||
VirtualSize:
|
||||
description: |-
|
||||
Total size of the image including all layers it is composed of.
|
||||
|
||||
Deprecated: this field is omitted in API v1.44, but kept for backward compatibility. Use Size instead.
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
example: 172064416
|
||||
Labels:
|
||||
description: "User-defined key/value metadata."
|
||||
type: "object"
|
||||
@ -2688,14 +2653,6 @@ definitions:
|
||||
description: |
|
||||
Unique ID of the build cache record.
|
||||
example: "ndlpt0hhvkqcdfkputsk4cq9c"
|
||||
Parent:
|
||||
description: |
|
||||
ID of the parent build cache record.
|
||||
|
||||
> **Deprecated**: This field is deprecated, and omitted if empty.
|
||||
type: "string"
|
||||
x-nullable: true
|
||||
example: ""
|
||||
Parents:
|
||||
description: |
|
||||
List of parent build cache record IDs.
|
||||
@ -3177,10 +3134,15 @@ definitions:
|
||||
- Args
|
||||
properties:
|
||||
DockerVersion:
|
||||
description: "Docker Version used to create the plugin"
|
||||
description: |-
|
||||
Docker Version used to create the plugin.
|
||||
|
||||
Depending on how the plugin was created, this field may be empty or omitted.
|
||||
|
||||
Deprecated: this field is no longer set, and will be removed in the next API version.
|
||||
type: "string"
|
||||
x-nullable: false
|
||||
example: "17.06.0-ce"
|
||||
x-omitempty: true
|
||||
Description:
|
||||
type: "string"
|
||||
x-nullable: false
|
||||
@ -6382,6 +6344,8 @@ definitions:
|
||||
|
||||
Kernel memory TCP limits are not supported when using cgroups v2, which
|
||||
does not support the corresponding `memory.kmem.tcp.limit_in_bytes` cgroup.
|
||||
|
||||
**Deprecated**: This field is deprecated as kernel 6.12 has deprecated kernel memory TCP accounting.
|
||||
type: "boolean"
|
||||
example: true
|
||||
CpuCfsPeriod:
|
||||
@ -6419,29 +6383,6 @@ definitions:
|
||||
description: "Indicates IPv4 forwarding is enabled."
|
||||
type: "boolean"
|
||||
example: true
|
||||
BridgeNfIptables:
|
||||
description: |
|
||||
Indicates if `bridge-nf-call-iptables` is available on the host when
|
||||
the daemon was started.
|
||||
|
||||
<p><br /></p>
|
||||
|
||||
> **Deprecated**: netfilter module is now loaded on-demand and no longer
|
||||
> during daemon startup, making this field obsolete. This field is always
|
||||
> `false` and will be removed in a API v1.49.
|
||||
type: "boolean"
|
||||
example: false
|
||||
BridgeNfIp6tables:
|
||||
description: |
|
||||
Indicates if `bridge-nf-call-ip6tables` is available on the host.
|
||||
|
||||
<p><br /></p>
|
||||
|
||||
> **Deprecated**: netfilter module is now loaded on-demand, and no longer
|
||||
> during daemon startup, making this field obsolete. This field is always
|
||||
> `false` and will be removed in a API v1.49.
|
||||
type: "boolean"
|
||||
example: false
|
||||
Debug:
|
||||
description: |
|
||||
Indicates if the daemon is running in debug-mode / with debug-level
|
||||
|
||||
7
vendor/github.com/docker/docker/api/types/container/hostconfig.go
generated
vendored
7
vendor/github.com/docker/docker/api/types/container/hostconfig.go
generated
vendored
@ -394,7 +394,12 @@ type Resources struct {
|
||||
|
||||
// KernelMemory specifies the kernel memory limit (in bytes) for the container.
|
||||
// Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes.
|
||||
KernelMemory int64 `json:",omitempty"`
|
||||
KernelMemory int64 `json:",omitempty"`
|
||||
// Hard limit for kernel TCP buffer memory (in bytes).
|
||||
//
|
||||
// Deprecated: This field is deprecated and will be removed in the next release.
|
||||
// Starting with 6.12, the kernel has deprecated kernel memory tcp accounting
|
||||
// for cgroups v1.
|
||||
KernelMemoryTCP int64 `json:",omitempty"` // Hard limit for kernel TCP buffer memory (in bytes)
|
||||
MemoryReservation int64 // Memory soft limit (in bytes)
|
||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap
|
||||
|
||||
4
vendor/github.com/docker/docker/api/types/image/image_inspect.go
generated
vendored
4
vendor/github.com/docker/docker/api/types/image/image_inspect.go
generated
vendored
@ -48,6 +48,8 @@ type InspectResponse struct {
|
||||
// Depending on how the image was created, this field may be empty and
|
||||
// is only set for images that were built/created locally. This field
|
||||
// is empty if the image was pulled from an image registry.
|
||||
//
|
||||
// Deprecated: this field is deprecated, and will be removed in the next release.
|
||||
Parent string
|
||||
|
||||
// Comment is an optional message that can be set when committing or
|
||||
@ -80,6 +82,8 @@ type InspectResponse struct {
|
||||
// DockerVersion is the version of Docker that was used to build the image.
|
||||
//
|
||||
// Depending on how the image was created, this field may be empty.
|
||||
//
|
||||
// Deprecated: this field is deprecated, and will be removed in the next release.
|
||||
DockerVersion string
|
||||
|
||||
// Author is the name of the author that was specified when committing the
|
||||
|
||||
6
vendor/github.com/docker/docker/api/types/plugin.go
generated
vendored
6
vendor/github.com/docker/docker/api/types/plugin.go
generated
vendored
@ -42,7 +42,11 @@ type PluginConfig struct {
|
||||
// Required: true
|
||||
Description string `json:"Description"`
|
||||
|
||||
// Docker Version used to create the plugin
|
||||
// Docker Version used to create the plugin.
|
||||
//
|
||||
// Depending on how the plugin was created, this field may be empty or omitted.
|
||||
//
|
||||
// Deprecated: this field is no longer set, and will be removed in the next API version.
|
||||
DockerVersion string `json:"DockerVersion,omitempty"`
|
||||
|
||||
// documentation
|
||||
|
||||
30
vendor/github.com/docker/docker/api/types/system/info.go
generated
vendored
30
vendor/github.com/docker/docker/api/types/system/info.go
generated
vendored
@ -9,19 +9,23 @@ import (
|
||||
// Info contains response of Engine API:
|
||||
// GET "/info"
|
||||
type Info struct {
|
||||
ID string
|
||||
Containers int
|
||||
ContainersRunning int
|
||||
ContainersPaused int
|
||||
ContainersStopped int
|
||||
Images int
|
||||
Driver string
|
||||
DriverStatus [][2]string
|
||||
SystemStatus [][2]string `json:",omitempty"` // SystemStatus is only propagated by the Swarm standalone API
|
||||
Plugins PluginsInfo
|
||||
MemoryLimit bool
|
||||
SwapLimit bool
|
||||
KernelMemory bool `json:",omitempty"` // Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes
|
||||
ID string
|
||||
Containers int
|
||||
ContainersRunning int
|
||||
ContainersPaused int
|
||||
ContainersStopped int
|
||||
Images int
|
||||
Driver string
|
||||
DriverStatus [][2]string
|
||||
SystemStatus [][2]string `json:",omitempty"` // SystemStatus is only propagated by the Swarm standalone API
|
||||
Plugins PluginsInfo
|
||||
MemoryLimit bool
|
||||
SwapLimit bool
|
||||
KernelMemory bool `json:",omitempty"` // Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes
|
||||
// KernelMemoryLimit is not supported on cgroups v2.
|
||||
//
|
||||
// Deprecated: This field is deprecated and will be removed in the next release.
|
||||
// Starting with kernel 6.12, the kernel has deprecated kernel memory tcp accounting
|
||||
KernelMemoryTCP bool `json:",omitempty"` // KernelMemoryTCP is not supported on cgroups v2.
|
||||
CPUCfsPeriod bool `json:"CpuCfsPeriod"`
|
||||
CPUCfsQuota bool `json:"CpuCfsQuota"`
|
||||
|
||||
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@ -163,7 +163,7 @@ github.com/decentral1se/passgen
|
||||
# github.com/distribution/reference v0.6.0
|
||||
## explicit; go 1.20
|
||||
github.com/distribution/reference
|
||||
# github.com/docker/cli v28.4.0+incompatible
|
||||
# github.com/docker/cli v28.4.0+incompatible => git.coopcloud.tech/p4u1/docker-cli v28.5.3-0.20260202112816-30df2d0b3a00+incompatible
|
||||
## explicit
|
||||
github.com/docker/cli/cli
|
||||
github.com/docker/cli/cli-plugins/metadata
|
||||
@ -213,7 +213,7 @@ github.com/docker/distribution/registry/client/auth/challenge
|
||||
github.com/docker/distribution/registry/client/transport
|
||||
github.com/docker/distribution/registry/storage/cache
|
||||
github.com/docker/distribution/registry/storage/cache/memory
|
||||
# github.com/docker/docker v28.4.0+incompatible
|
||||
# github.com/docker/docker v28.5.2+incompatible
|
||||
## explicit
|
||||
github.com/docker/docker/api
|
||||
github.com/docker/docker/api/types
|
||||
|
||||
Reference in New Issue
Block a user