mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	Merge pull request #3071 from thaJeztah/bump_engine_28.0.2
vendor: github.com/docker/docker, docker/cli v28.0.2
This commit is contained in:
		@@ -11,7 +11,7 @@ import (
 | 
				
			|||||||
	"github.com/docker/buildx/util/desktop"
 | 
						"github.com/docker/buildx/util/desktop"
 | 
				
			||||||
	"github.com/docker/buildx/version"
 | 
						"github.com/docker/buildx/version"
 | 
				
			||||||
	"github.com/docker/cli/cli"
 | 
						"github.com/docker/cli/cli"
 | 
				
			||||||
	"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-plugins/plugin"
 | 
				
			||||||
	"github.com/docker/cli/cli/command"
 | 
						"github.com/docker/cli/cli/command"
 | 
				
			||||||
	"github.com/docker/cli/cli/debug"
 | 
						"github.com/docker/cli/cli/debug"
 | 
				
			||||||
@@ -64,7 +64,7 @@ func flushMetrics(cmd *command.DockerCli) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func runPlugin(cmd *command.DockerCli) error {
 | 
					func runPlugin(cmd *command.DockerCli) error {
 | 
				
			||||||
	rootCmd := commands.NewRootCmd("buildx", true, cmd)
 | 
						rootCmd := commands.NewRootCmd("buildx", true, cmd)
 | 
				
			||||||
	return plugin.RunPlugin(cmd, rootCmd, manager.Metadata{
 | 
						return plugin.RunPlugin(cmd, rootCmd, metadata.Metadata{
 | 
				
			||||||
		SchemaVersion: "0.1.0",
 | 
							SchemaVersion: "0.1.0",
 | 
				
			||||||
		Vendor:        "Docker Inc.",
 | 
							Vendor:        "Docker Inc.",
 | 
				
			||||||
		Version:       version.Version,
 | 
							Version:       version.Version,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								go.mod
									
									
									
									
									
								
							@@ -8,7 +8,7 @@ require (
 | 
				
			|||||||
	github.com/aws/aws-sdk-go-v2/config v1.27.27
 | 
						github.com/aws/aws-sdk-go-v2/config v1.27.27
 | 
				
			||||||
	github.com/compose-spec/compose-go/v2 v2.4.8
 | 
						github.com/compose-spec/compose-go/v2 v2.4.8
 | 
				
			||||||
	github.com/containerd/console v1.0.4
 | 
						github.com/containerd/console v1.0.4
 | 
				
			||||||
	github.com/containerd/containerd/v2 v2.0.3
 | 
						github.com/containerd/containerd/v2 v2.0.4
 | 
				
			||||||
	github.com/containerd/continuity v0.4.5
 | 
						github.com/containerd/continuity v0.4.5
 | 
				
			||||||
	github.com/containerd/errdefs v1.0.0
 | 
						github.com/containerd/errdefs v1.0.0
 | 
				
			||||||
	github.com/containerd/log v0.1.0
 | 
						github.com/containerd/log v0.1.0
 | 
				
			||||||
@@ -17,9 +17,9 @@ require (
 | 
				
			|||||||
	github.com/creack/pty v1.1.24
 | 
						github.com/creack/pty v1.1.24
 | 
				
			||||||
	github.com/davecgh/go-spew v1.1.1
 | 
						github.com/davecgh/go-spew v1.1.1
 | 
				
			||||||
	github.com/distribution/reference v0.6.0
 | 
						github.com/distribution/reference v0.6.0
 | 
				
			||||||
	github.com/docker/cli v28.0.1+incompatible
 | 
						github.com/docker/cli v28.0.2+incompatible
 | 
				
			||||||
	github.com/docker/cli-docs-tool v0.9.0
 | 
						github.com/docker/cli-docs-tool v0.9.0
 | 
				
			||||||
	github.com/docker/docker v28.0.1+incompatible
 | 
						github.com/docker/docker v28.0.2+incompatible
 | 
				
			||||||
	github.com/docker/go-units v0.5.0
 | 
						github.com/docker/go-units v0.5.0
 | 
				
			||||||
	github.com/gofrs/flock v0.12.1
 | 
						github.com/gofrs/flock v0.12.1
 | 
				
			||||||
	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
 | 
						github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								go.sum
									
									
									
									
									
								
							@@ -85,8 +85,8 @@ github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn
 | 
				
			|||||||
github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
 | 
					github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
 | 
				
			||||||
github.com/containerd/containerd/api v1.8.0 h1:hVTNJKR8fMc/2Tiw60ZRijntNMd1U+JVMyTRdsD2bS0=
 | 
					github.com/containerd/containerd/api v1.8.0 h1:hVTNJKR8fMc/2Tiw60ZRijntNMd1U+JVMyTRdsD2bS0=
 | 
				
			||||||
github.com/containerd/containerd/api v1.8.0/go.mod h1:dFv4lt6S20wTu/hMcP4350RL87qPWLVa/OHOwmmdnYc=
 | 
					github.com/containerd/containerd/api v1.8.0/go.mod h1:dFv4lt6S20wTu/hMcP4350RL87qPWLVa/OHOwmmdnYc=
 | 
				
			||||||
github.com/containerd/containerd/v2 v2.0.3 h1:zBKgwgZsuu+LPCMzCLgA4sC4MiZzZ59ZT31XkmiISQM=
 | 
					github.com/containerd/containerd/v2 v2.0.4 h1:+r7yJMwhTfMm3CDyiBjMBQO8a9CTBxL2Bg/JtqtIwB8=
 | 
				
			||||||
github.com/containerd/containerd/v2 v2.0.3/go.mod h1:5j9QUUaV/cy9ZeAx4S+8n9ffpf+iYnEj4jiExgcbuLY=
 | 
					github.com/containerd/containerd/v2 v2.0.4/go.mod h1:5j9QUUaV/cy9ZeAx4S+8n9ffpf+iYnEj4jiExgcbuLY=
 | 
				
			||||||
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
 | 
					github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
 | 
				
			||||||
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
 | 
					github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
 | 
				
			||||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
 | 
					github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
 | 
				
			||||||
@@ -122,15 +122,15 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 | 
				
			|||||||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
 | 
					github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
 | 
				
			||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
 | 
					github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
 | 
				
			||||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
 | 
					github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
 | 
				
			||||||
github.com/docker/cli v28.0.1+incompatible h1:g0h5NQNda3/CxIsaZfH4Tyf6vpxFth7PYl3hgCPOKzs=
 | 
					github.com/docker/cli v28.0.2+incompatible h1:cRPZ77FK3/IXTAIQQj1vmhlxiLS5m+MIUDwS6f57lrE=
 | 
				
			||||||
github.com/docker/cli v28.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 | 
					github.com/docker/cli v28.0.2+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 h1:CVwQbE+ZziwlPqrJ7LRyUF6GvCA+6gj7MTCsayaK9t0=
 | 
				
			||||||
github.com/docker/cli-docs-tool v0.9.0/go.mod h1:ClrwlNW+UioiRyH9GiAOe1o3J/TsY3Tr1ipoypjAUtc=
 | 
					github.com/docker/cli-docs-tool v0.9.0/go.mod h1:ClrwlNW+UioiRyH9GiAOe1o3J/TsY3Tr1ipoypjAUtc=
 | 
				
			||||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
					github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
				
			||||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
 | 
					github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
 | 
				
			||||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
					github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
				
			||||||
github.com/docker/docker v28.0.1+incompatible h1:FCHjSRdXhNRFjlHMTv4jUNlIBbTeRjrWfeFuJp7jpo0=
 | 
					github.com/docker/docker v28.0.2+incompatible h1:9BILleFwug5FSSqWBgVevgL3ewDJfWWWyZVqlDMttE8=
 | 
				
			||||||
github.com/docker/docker v28.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 | 
					github.com/docker/docker v28.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 | 
				
			||||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
 | 
					github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
 | 
				
			||||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
 | 
					github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
 | 
				
			||||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
 | 
					github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								vendor/github.com/containerd/containerd/v2/core/images/image.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/containerd/containerd/v2/core/images/image.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -369,8 +369,8 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return append([]ocispec.Descriptor{}, index.Manifests...), nil
 | 
							return append([]ocispec.Descriptor{}, index.Manifests...), nil
 | 
				
			||||||
	} else if !IsLayerType(desc.MediaType) && !IsKnownConfig(desc.MediaType) {
 | 
						} else if !IsLayerType(desc.MediaType) && !IsKnownConfig(desc.MediaType) && !IsAttestationType(desc.MediaType) {
 | 
				
			||||||
		// Layers and configs are childless data types and should not be logged.
 | 
							// Layers, configs, and attestations are childless data types and should not be logged.
 | 
				
			||||||
		log.G(ctx).Debugf("encountered unknown type %v; children may not be fetched", desc.MediaType)
 | 
							log.G(ctx).Debugf("encountered unknown type %v; children may not be fetched", desc.MediaType)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil, nil
 | 
						return nil, nil
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								vendor/github.com/containerd/containerd/v2/core/images/mediatypes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/containerd/containerd/v2/core/images/mediatypes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -58,6 +58,9 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	MediaTypeImageLayerEncrypted     = ocispec.MediaTypeImageLayer + "+encrypted"
 | 
						MediaTypeImageLayerEncrypted     = ocispec.MediaTypeImageLayer + "+encrypted"
 | 
				
			||||||
	MediaTypeImageLayerGzipEncrypted = ocispec.MediaTypeImageLayerGzip + "+encrypted"
 | 
						MediaTypeImageLayerGzipEncrypted = ocispec.MediaTypeImageLayerGzip + "+encrypted"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// In-toto attestation
 | 
				
			||||||
 | 
						MediaTypeInToto = "application/vnd.in-toto+json"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DiffCompression returns the compression as defined by the layer diff media
 | 
					// DiffCompression returns the compression as defined by the layer diff media
 | 
				
			||||||
@@ -193,6 +196,16 @@ func IsKnownConfig(mt string) bool {
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsAttestationType returns true if the media type is an attestation type
 | 
				
			||||||
 | 
					func IsAttestationType(mt string) bool {
 | 
				
			||||||
 | 
						switch mt {
 | 
				
			||||||
 | 
						case MediaTypeInToto:
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ChildGCLabels returns the label for a given descriptor to reference it
 | 
					// ChildGCLabels returns the label for a given descriptor to reference it
 | 
				
			||||||
func ChildGCLabels(desc ocispec.Descriptor) []string {
 | 
					func ChildGCLabels(desc ocispec.Descriptor) []string {
 | 
				
			||||||
	mt := desc.MediaType
 | 
						mt := desc.MediaType
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/v2/core/remotes/handlers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/v2/core/remotes/handlers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -80,6 +80,8 @@ func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
 | 
				
			|||||||
		return "layer-" + key
 | 
							return "layer-" + key
 | 
				
			||||||
	case images.IsKnownConfig(desc.MediaType):
 | 
						case images.IsKnownConfig(desc.MediaType):
 | 
				
			||||||
		return "config-" + key
 | 
							return "config-" + key
 | 
				
			||||||
 | 
						case images.IsAttestationType(desc.MediaType):
 | 
				
			||||||
 | 
							return "attestation-" + key
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		log.G(ctx).Warnf("reference for unknown type: %s", desc.MediaType)
 | 
							log.G(ctx).Warnf("reference for unknown type: %s", desc.MediaType)
 | 
				
			||||||
		return "unknown-" + key
 | 
							return "unknown-" + key
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								vendor/github.com/containerd/containerd/v2/version/version.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/containerd/containerd/v2/version/version.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -19,11 +19,12 @@ package version
 | 
				
			|||||||
import "runtime"
 | 
					import "runtime"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
 | 
						Name = "containerd"
 | 
				
			||||||
	// Package is filled at linking time
 | 
						// Package is filled at linking time
 | 
				
			||||||
	Package = "github.com/containerd/containerd/v2"
 | 
						Package = "github.com/containerd/containerd/v2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Version holds the complete version number. Filled in at linking time.
 | 
						// Version holds the complete version number. Filled in at linking time.
 | 
				
			||||||
	Version = "2.0.3+unknown"
 | 
						Version = "2.0.4+unknown"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Revision is filled with the VCS (e.g. git) revision being used to build
 | 
						// Revision is filled with the VCS (e.g. git) revision being used to build
 | 
				
			||||||
	// the program at linking time.
 | 
						// the program at linking time.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								vendor/github.com/docker/cli/cli-plugins/hooks/printer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/docker/cli/cli-plugins/hooks/printer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,18 +0,0 @@
 | 
				
			|||||||
package hooks
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/morikuni/aec"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func PrintNextSteps(out io.Writer, messages []string) {
 | 
					 | 
				
			||||||
	if len(messages) == 0 {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	_, _ = fmt.Fprintln(out, aec.Bold.Apply("\nWhat's next:"))
 | 
					 | 
				
			||||||
	for _, n := range messages {
 | 
					 | 
				
			||||||
		_, _ = fmt.Fprintln(out, "   ", n)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										116
									
								
								vendor/github.com/docker/cli/cli-plugins/hooks/template.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										116
									
								
								vendor/github.com/docker/cli/cli-plugins/hooks/template.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,116 +0,0 @@
 | 
				
			|||||||
package hooks
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"bytes"
 | 
					 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"text/template"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type HookType int
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	NextSteps = iota
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// HookMessage represents a plugin hook response. Plugins
 | 
					 | 
				
			||||||
// declaring support for CLI hooks need to print a json
 | 
					 | 
				
			||||||
// representation of this type when their hook subcommand
 | 
					 | 
				
			||||||
// is invoked.
 | 
					 | 
				
			||||||
type HookMessage struct {
 | 
					 | 
				
			||||||
	Type     HookType
 | 
					 | 
				
			||||||
	Template string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TemplateReplaceSubcommandName returns a hook template string
 | 
					 | 
				
			||||||
// that will be replaced by the CLI subcommand being executed
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Example:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// "you ran the subcommand: " + TemplateReplaceSubcommandName()
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// when being executed after the command:
 | 
					 | 
				
			||||||
// `docker run --name "my-container" alpine`
 | 
					 | 
				
			||||||
// will result in the message:
 | 
					 | 
				
			||||||
// `you ran the subcommand: run`
 | 
					 | 
				
			||||||
func TemplateReplaceSubcommandName() string {
 | 
					 | 
				
			||||||
	return hookTemplateCommandName
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TemplateReplaceFlagValue returns a hook template string
 | 
					 | 
				
			||||||
// that will be replaced by the flags value.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Example:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// "you ran a container named: " + TemplateReplaceFlagValue("name")
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// when being executed after the command:
 | 
					 | 
				
			||||||
// `docker run --name "my-container" alpine`
 | 
					 | 
				
			||||||
// will result in the message:
 | 
					 | 
				
			||||||
// `you ran a container named: my-container`
 | 
					 | 
				
			||||||
func TemplateReplaceFlagValue(flag string) string {
 | 
					 | 
				
			||||||
	return fmt.Sprintf(hookTemplateFlagValue, flag)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TemplateReplaceArg takes an index i and returns a hook
 | 
					 | 
				
			||||||
// template string that the CLI will replace the template with
 | 
					 | 
				
			||||||
// the ith argument, after processing the passed flags.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Example:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// "run this image with `docker run " + TemplateReplaceArg(0) + "`"
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// when being executed after the command:
 | 
					 | 
				
			||||||
// `docker pull alpine`
 | 
					 | 
				
			||||||
// will result in the message:
 | 
					 | 
				
			||||||
// "Run this image with `docker run alpine`"
 | 
					 | 
				
			||||||
func TemplateReplaceArg(i int) string {
 | 
					 | 
				
			||||||
	return fmt.Sprintf(hookTemplateArg, strconv.Itoa(i))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func ParseTemplate(hookTemplate string, cmd *cobra.Command) ([]string, error) {
 | 
					 | 
				
			||||||
	tmpl := template.New("").Funcs(commandFunctions)
 | 
					 | 
				
			||||||
	tmpl, err := tmpl.Parse(hookTemplate)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	b := bytes.Buffer{}
 | 
					 | 
				
			||||||
	err = tmpl.Execute(&b, cmd)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return strings.Split(b.String(), "\n"), nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var ErrHookTemplateParse = errors.New("failed to parse hook template")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	hookTemplateCommandName = "{{.Name}}"
 | 
					 | 
				
			||||||
	hookTemplateFlagValue   = `{{flag . "%s"}}`
 | 
					 | 
				
			||||||
	hookTemplateArg         = "{{arg . %s}}"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var commandFunctions = template.FuncMap{
 | 
					 | 
				
			||||||
	"flag": getFlagValue,
 | 
					 | 
				
			||||||
	"arg":  getArgValue,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getFlagValue(cmd *cobra.Command, flag string) (string, error) {
 | 
					 | 
				
			||||||
	cmdFlag := cmd.Flag(flag)
 | 
					 | 
				
			||||||
	if cmdFlag == nil {
 | 
					 | 
				
			||||||
		return "", ErrHookTemplateParse
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return cmdFlag.Value.String(), nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getArgValue(cmd *cobra.Command, i int) (string, error) {
 | 
					 | 
				
			||||||
	flags := cmd.Flags()
 | 
					 | 
				
			||||||
	if flags == nil {
 | 
					 | 
				
			||||||
		return "", ErrHookTemplateParse
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return flags.Arg(i), nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										21
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/candidate.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/candidate.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,21 +0,0 @@
 | 
				
			|||||||
package manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import "os/exec"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Candidate represents a possible plugin candidate, for mocking purposes
 | 
					 | 
				
			||||||
type Candidate interface {
 | 
					 | 
				
			||||||
	Path() string
 | 
					 | 
				
			||||||
	Metadata() ([]byte, error)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type candidate struct {
 | 
					 | 
				
			||||||
	path string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *candidate) Path() string {
 | 
					 | 
				
			||||||
	return c.path
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *candidate) Metadata() ([]byte, error) {
 | 
					 | 
				
			||||||
	return exec.Command(c.path, MetadataSubcommandName).Output() // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										147
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/cobra.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										147
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/cobra.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,147 +0,0 @@
 | 
				
			|||||||
package manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"net/url"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"sync"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/docker/cli/cli/command"
 | 
					 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
					 | 
				
			||||||
	"go.opentelemetry.io/otel/attribute"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	// CommandAnnotationPlugin is added to every stub command added by
 | 
					 | 
				
			||||||
	// AddPluginCommandStubs with the value "true" and so can be
 | 
					 | 
				
			||||||
	// used to distinguish plugin stubs from regular commands.
 | 
					 | 
				
			||||||
	CommandAnnotationPlugin = "com.docker.cli.plugin"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CommandAnnotationPluginVendor is added to every stub command
 | 
					 | 
				
			||||||
	// added by AddPluginCommandStubs and contains the vendor of
 | 
					 | 
				
			||||||
	// that plugin.
 | 
					 | 
				
			||||||
	CommandAnnotationPluginVendor = "com.docker.cli.plugin.vendor"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CommandAnnotationPluginVersion is added to every stub command
 | 
					 | 
				
			||||||
	// added by AddPluginCommandStubs and contains the version of
 | 
					 | 
				
			||||||
	// that plugin.
 | 
					 | 
				
			||||||
	CommandAnnotationPluginVersion = "com.docker.cli.plugin.version"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CommandAnnotationPluginInvalid is added to any stub command
 | 
					 | 
				
			||||||
	// added by AddPluginCommandStubs for an invalid command (that
 | 
					 | 
				
			||||||
	// is, one which failed it's candidate test) and contains the
 | 
					 | 
				
			||||||
	// reason for the failure.
 | 
					 | 
				
			||||||
	CommandAnnotationPluginInvalid = "com.docker.cli.plugin-invalid"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CommandAnnotationPluginCommandPath is added to overwrite the
 | 
					 | 
				
			||||||
	// command path for a plugin invocation.
 | 
					 | 
				
			||||||
	CommandAnnotationPluginCommandPath = "com.docker.cli.plugin.command_path"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var pluginCommandStubsOnce sync.Once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// AddPluginCommandStubs adds a stub cobra.Commands for each valid and invalid
 | 
					 | 
				
			||||||
// plugin. The command stubs will have several annotations added, see
 | 
					 | 
				
			||||||
// `CommandAnnotationPlugin*`.
 | 
					 | 
				
			||||||
func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) (err error) {
 | 
					 | 
				
			||||||
	pluginCommandStubsOnce.Do(func() {
 | 
					 | 
				
			||||||
		var plugins []Plugin
 | 
					 | 
				
			||||||
		plugins, err = ListPlugins(dockerCli, rootCmd)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		for _, p := range plugins {
 | 
					 | 
				
			||||||
			vendor := p.Vendor
 | 
					 | 
				
			||||||
			if vendor == "" {
 | 
					 | 
				
			||||||
				vendor = "unknown"
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			annotations := map[string]string{
 | 
					 | 
				
			||||||
				CommandAnnotationPlugin:        "true",
 | 
					 | 
				
			||||||
				CommandAnnotationPluginVendor:  vendor,
 | 
					 | 
				
			||||||
				CommandAnnotationPluginVersion: p.Version,
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if p.Err != nil {
 | 
					 | 
				
			||||||
				annotations[CommandAnnotationPluginInvalid] = p.Err.Error()
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			rootCmd.AddCommand(&cobra.Command{
 | 
					 | 
				
			||||||
				Use:                p.Name,
 | 
					 | 
				
			||||||
				Short:              p.ShortDescription,
 | 
					 | 
				
			||||||
				Run:                func(_ *cobra.Command, _ []string) {},
 | 
					 | 
				
			||||||
				Annotations:        annotations,
 | 
					 | 
				
			||||||
				DisableFlagParsing: true,
 | 
					 | 
				
			||||||
				RunE: func(cmd *cobra.Command, args []string) error {
 | 
					 | 
				
			||||||
					flags := rootCmd.PersistentFlags()
 | 
					 | 
				
			||||||
					flags.SetOutput(nil)
 | 
					 | 
				
			||||||
					perr := flags.Parse(args)
 | 
					 | 
				
			||||||
					if perr != nil {
 | 
					 | 
				
			||||||
						return err
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					if flags.Changed("help") {
 | 
					 | 
				
			||||||
						cmd.HelpFunc()(rootCmd, args)
 | 
					 | 
				
			||||||
						return nil
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					return fmt.Errorf("docker: unknown command: docker %s\n\nRun 'docker --help' for more information", cmd.Name())
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 | 
					 | 
				
			||||||
					// Delegate completion to plugin
 | 
					 | 
				
			||||||
					cargs := []string{p.Path, cobra.ShellCompRequestCmd, p.Name}
 | 
					 | 
				
			||||||
					cargs = append(cargs, args...)
 | 
					 | 
				
			||||||
					cargs = append(cargs, toComplete)
 | 
					 | 
				
			||||||
					os.Args = cargs
 | 
					 | 
				
			||||||
					runCommand, runErr := PluginRunCommand(dockerCli, p.Name, cmd)
 | 
					 | 
				
			||||||
					if runErr != nil {
 | 
					 | 
				
			||||||
						return nil, cobra.ShellCompDirectiveError
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					runErr = runCommand.Run()
 | 
					 | 
				
			||||||
					if runErr == nil {
 | 
					 | 
				
			||||||
						os.Exit(0) // plugin already rendered complete data
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					return nil, cobra.ShellCompDirectiveError
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	return err
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	dockerCliAttributePrefix = attribute.Key("docker.cli")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cobraCommandPath = attribute.Key("cobra.command_path")
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getPluginResourceAttributes(cmd *cobra.Command, plugin Plugin) attribute.Set {
 | 
					 | 
				
			||||||
	commandPath := cmd.Annotations[CommandAnnotationPluginCommandPath]
 | 
					 | 
				
			||||||
	if commandPath == "" {
 | 
					 | 
				
			||||||
		commandPath = fmt.Sprintf("%s %s", cmd.CommandPath(), plugin.Name)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	attrSet := attribute.NewSet(
 | 
					 | 
				
			||||||
		cobraCommandPath.String(commandPath),
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	kvs := make([]attribute.KeyValue, 0, attrSet.Len())
 | 
					 | 
				
			||||||
	for iter := attrSet.Iter(); iter.Next(); {
 | 
					 | 
				
			||||||
		attr := iter.Attribute()
 | 
					 | 
				
			||||||
		kvs = append(kvs, attribute.KeyValue{
 | 
					 | 
				
			||||||
			Key:   dockerCliAttributePrefix + "." + attr.Key,
 | 
					 | 
				
			||||||
			Value: attr.Value,
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return attribute.NewSet(kvs...)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func appendPluginResourceAttributesEnvvar(env []string, cmd *cobra.Command, plugin Plugin) []string {
 | 
					 | 
				
			||||||
	if attrs := getPluginResourceAttributes(cmd, plugin); attrs.Len() > 0 {
 | 
					 | 
				
			||||||
		// values in environment variables need to be in baggage format
 | 
					 | 
				
			||||||
		// otel/baggage package can be used after update to v1.22, currently it encodes incorrectly
 | 
					 | 
				
			||||||
		attrsSlice := make([]string, attrs.Len())
 | 
					 | 
				
			||||||
		for iter := attrs.Iter(); iter.Next(); {
 | 
					 | 
				
			||||||
			i, v := iter.IndexedAttribute()
 | 
					 | 
				
			||||||
			attrsSlice[i] = string(v.Key) + "=" + url.PathEscape(v.Value.AsString())
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		env = append(env, ResourceAttributesEnvvar+"="+strings.Join(attrsSlice, ","))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return env
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										54
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,54 +0,0 @@
 | 
				
			|||||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
 | 
					 | 
				
			||||||
//go:build go1.22
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// pluginError is set as Plugin.Err by NewPlugin if the plugin
 | 
					 | 
				
			||||||
// candidate fails one of the candidate tests. This exists primarily
 | 
					 | 
				
			||||||
// to implement encoding.TextMarshaller such that rendering a plugin as JSON
 | 
					 | 
				
			||||||
// (e.g. for `docker info -f '{{json .CLIPlugins}}'`) renders the Err
 | 
					 | 
				
			||||||
// field as a useful string and not just `{}`. See
 | 
					 | 
				
			||||||
// https://github.com/golang/go/issues/10748 for some discussion
 | 
					 | 
				
			||||||
// around why the builtin error type doesn't implement this.
 | 
					 | 
				
			||||||
type pluginError struct {
 | 
					 | 
				
			||||||
	cause error
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Error satisfies the core error interface for pluginError.
 | 
					 | 
				
			||||||
func (e *pluginError) Error() string {
 | 
					 | 
				
			||||||
	return e.cause.Error()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Cause satisfies the errors.causer interface for pluginError.
 | 
					 | 
				
			||||||
func (e *pluginError) Cause() error {
 | 
					 | 
				
			||||||
	return e.cause
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Unwrap provides compatibility for Go 1.13 error chains.
 | 
					 | 
				
			||||||
func (e *pluginError) Unwrap() error {
 | 
					 | 
				
			||||||
	return e.cause
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// MarshalText marshalls the pluginError into a textual form.
 | 
					 | 
				
			||||||
func (e *pluginError) MarshalText() (text []byte, err error) {
 | 
					 | 
				
			||||||
	return []byte(e.cause.Error()), nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// wrapAsPluginError wraps an error in a pluginError with an
 | 
					 | 
				
			||||||
// additional message, analogous to errors.Wrapf.
 | 
					 | 
				
			||||||
func wrapAsPluginError(err error, msg string) error {
 | 
					 | 
				
			||||||
	if err == nil {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return &pluginError{cause: errors.Wrap(err, msg)}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// NewPluginError creates a new pluginError, analogous to
 | 
					 | 
				
			||||||
// errors.Errorf.
 | 
					 | 
				
			||||||
func NewPluginError(msg string, args ...any) error {
 | 
					 | 
				
			||||||
	return &pluginError{cause: errors.Errorf(msg, args...)}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										199
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/hooks.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										199
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/hooks.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,199 +0,0 @@
 | 
				
			|||||||
package manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"context"
 | 
					 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/docker/cli/cli-plugins/hooks"
 | 
					 | 
				
			||||||
	"github.com/docker/cli/cli/command"
 | 
					 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
					 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
					 | 
				
			||||||
	"github.com/spf13/pflag"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// HookPluginData is the type representing the information
 | 
					 | 
				
			||||||
// that plugins declaring support for hooks get passed when
 | 
					 | 
				
			||||||
// being invoked following a CLI command execution.
 | 
					 | 
				
			||||||
type HookPluginData struct {
 | 
					 | 
				
			||||||
	// RootCmd is a string representing the matching hook configuration
 | 
					 | 
				
			||||||
	// which is currently being invoked. If a hook for `docker context` is
 | 
					 | 
				
			||||||
	// configured and the user executes `docker context ls`, the plugin will
 | 
					 | 
				
			||||||
	// be invoked with `context`.
 | 
					 | 
				
			||||||
	RootCmd      string
 | 
					 | 
				
			||||||
	Flags        map[string]string
 | 
					 | 
				
			||||||
	CommandError string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// RunCLICommandHooks is the entrypoint into the hooks execution flow after
 | 
					 | 
				
			||||||
// a main CLI command was executed. It calls the hook subcommand for all
 | 
					 | 
				
			||||||
// present CLI plugins that declare support for hooks in their metadata and
 | 
					 | 
				
			||||||
// parses/prints their responses.
 | 
					 | 
				
			||||||
func RunCLICommandHooks(ctx context.Context, dockerCli command.Cli, rootCmd, subCommand *cobra.Command, cmdErrorMessage string) {
 | 
					 | 
				
			||||||
	commandName := strings.TrimPrefix(subCommand.CommandPath(), rootCmd.Name()+" ")
 | 
					 | 
				
			||||||
	flags := getCommandFlags(subCommand)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	runHooks(ctx, dockerCli, rootCmd, subCommand, commandName, flags, cmdErrorMessage)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// RunPluginHooks is the entrypoint for the hooks execution flow
 | 
					 | 
				
			||||||
// after a plugin command was just executed by the CLI.
 | 
					 | 
				
			||||||
func RunPluginHooks(ctx context.Context, dockerCli command.Cli, rootCmd, subCommand *cobra.Command, args []string) {
 | 
					 | 
				
			||||||
	commandName := strings.Join(args, " ")
 | 
					 | 
				
			||||||
	flags := getNaiveFlags(args)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	runHooks(ctx, dockerCli, rootCmd, subCommand, commandName, flags, "")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func runHooks(ctx context.Context, dockerCli command.Cli, rootCmd, subCommand *cobra.Command, invokedCommand string, flags map[string]string, cmdErrorMessage string) {
 | 
					 | 
				
			||||||
	nextSteps := invokeAndCollectHooks(ctx, dockerCli, rootCmd, subCommand, invokedCommand, flags, cmdErrorMessage)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hooks.PrintNextSteps(dockerCli.Err(), nextSteps)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func invokeAndCollectHooks(ctx context.Context, dockerCli command.Cli, rootCmd, subCmd *cobra.Command, subCmdStr string, flags map[string]string, cmdErrorMessage string) []string {
 | 
					 | 
				
			||||||
	// check if the context was cancelled before invoking hooks
 | 
					 | 
				
			||||||
	select {
 | 
					 | 
				
			||||||
	case <-ctx.Done():
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pluginsCfg := dockerCli.ConfigFile().Plugins
 | 
					 | 
				
			||||||
	if pluginsCfg == nil {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	nextSteps := make([]string, 0, len(pluginsCfg))
 | 
					 | 
				
			||||||
	for pluginName, cfg := range pluginsCfg {
 | 
					 | 
				
			||||||
		match, ok := pluginMatch(cfg, subCmdStr)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		p, err := GetPlugin(pluginName, dockerCli, rootCmd)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		hookReturn, err := p.RunHook(ctx, HookPluginData{
 | 
					 | 
				
			||||||
			RootCmd:      match,
 | 
					 | 
				
			||||||
			Flags:        flags,
 | 
					 | 
				
			||||||
			CommandError: cmdErrorMessage,
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			// skip misbehaving plugins, but don't halt execution
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var hookMessageData hooks.HookMessage
 | 
					 | 
				
			||||||
		err = json.Unmarshal(hookReturn, &hookMessageData)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// currently the only hook type
 | 
					 | 
				
			||||||
		if hookMessageData.Type != hooks.NextSteps {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		processedHook, err := hooks.ParseTemplate(hookMessageData.Template, subCmd)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var appended bool
 | 
					 | 
				
			||||||
		nextSteps, appended = appendNextSteps(nextSteps, processedHook)
 | 
					 | 
				
			||||||
		if !appended {
 | 
					 | 
				
			||||||
			logrus.Debugf("Plugin %s responded with an empty hook message %q. Ignoring.", pluginName, string(hookReturn))
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nextSteps
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// appendNextSteps appends the processed hook output to the nextSteps slice.
 | 
					 | 
				
			||||||
// If the processed hook output is empty, it is not appended.
 | 
					 | 
				
			||||||
// Empty lines are not stripped if there's at least one non-empty line.
 | 
					 | 
				
			||||||
func appendNextSteps(nextSteps []string, processed []string) ([]string, bool) {
 | 
					 | 
				
			||||||
	empty := true
 | 
					 | 
				
			||||||
	for _, l := range processed {
 | 
					 | 
				
			||||||
		if strings.TrimSpace(l) != "" {
 | 
					 | 
				
			||||||
			empty = false
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if empty {
 | 
					 | 
				
			||||||
		return nextSteps, false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return append(nextSteps, processed...), true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// pluginMatch takes a plugin configuration and a string representing the
 | 
					 | 
				
			||||||
// command being executed (such as 'image ls' – the root 'docker' is omitted)
 | 
					 | 
				
			||||||
// and, if the configuration includes a hook for the invoked command, returns
 | 
					 | 
				
			||||||
// the configured hook string.
 | 
					 | 
				
			||||||
func pluginMatch(pluginCfg map[string]string, subCmd string) (string, bool) {
 | 
					 | 
				
			||||||
	configuredPluginHooks, ok := pluginCfg["hooks"]
 | 
					 | 
				
			||||||
	if !ok || configuredPluginHooks == "" {
 | 
					 | 
				
			||||||
		return "", false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	commands := strings.Split(configuredPluginHooks, ",")
 | 
					 | 
				
			||||||
	for _, hookCmd := range commands {
 | 
					 | 
				
			||||||
		if hookMatch(hookCmd, subCmd) {
 | 
					 | 
				
			||||||
			return hookCmd, true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return "", false
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func hookMatch(hookCmd, subCmd string) bool {
 | 
					 | 
				
			||||||
	hookCmdTokens := strings.Split(hookCmd, " ")
 | 
					 | 
				
			||||||
	subCmdTokens := strings.Split(subCmd, " ")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(hookCmdTokens) > len(subCmdTokens) {
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for i, v := range hookCmdTokens {
 | 
					 | 
				
			||||||
		if v != subCmdTokens[i] {
 | 
					 | 
				
			||||||
			return false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getCommandFlags(cmd *cobra.Command) map[string]string {
 | 
					 | 
				
			||||||
	flags := make(map[string]string)
 | 
					 | 
				
			||||||
	cmd.Flags().Visit(func(f *pflag.Flag) {
 | 
					 | 
				
			||||||
		var fValue string
 | 
					 | 
				
			||||||
		if f.Value.Type() == "bool" {
 | 
					 | 
				
			||||||
			fValue = f.Value.String()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		flags[f.Name] = fValue
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	return flags
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// getNaiveFlags string-matches argv and parses them into a map.
 | 
					 | 
				
			||||||
// This is used when calling hooks after a plugin command, since
 | 
					 | 
				
			||||||
// in this case we can't rely on the cobra command tree to parse
 | 
					 | 
				
			||||||
// flags in this case. In this case, no values are ever passed,
 | 
					 | 
				
			||||||
// since we don't have enough information to process them.
 | 
					 | 
				
			||||||
func getNaiveFlags(args []string) map[string]string {
 | 
					 | 
				
			||||||
	flags := make(map[string]string)
 | 
					 | 
				
			||||||
	for _, arg := range args {
 | 
					 | 
				
			||||||
		if strings.HasPrefix(arg, "--") {
 | 
					 | 
				
			||||||
			flags[arg[2:]] = ""
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if strings.HasPrefix(arg, "-") {
 | 
					 | 
				
			||||||
			flags[arg[1:]] = ""
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return flags
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										247
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										247
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,247 +0,0 @@
 | 
				
			|||||||
package manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"context"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"os/exec"
 | 
					 | 
				
			||||||
	"path/filepath"
 | 
					 | 
				
			||||||
	"sort"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"sync"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/docker/cli/cli/command"
 | 
					 | 
				
			||||||
	"github.com/docker/cli/cli/config"
 | 
					 | 
				
			||||||
	"github.com/docker/cli/cli/config/configfile"
 | 
					 | 
				
			||||||
	"github.com/fvbommel/sortorder"
 | 
					 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
					 | 
				
			||||||
	"golang.org/x/sync/errgroup"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	// ReexecEnvvar is the name of an ennvar which is set to the command
 | 
					 | 
				
			||||||
	// used to originally invoke the docker CLI when executing a
 | 
					 | 
				
			||||||
	// plugin. Assuming $PATH and $CWD remain unchanged this should allow
 | 
					 | 
				
			||||||
	// the plugin to re-execute the original CLI.
 | 
					 | 
				
			||||||
	ReexecEnvvar = "DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ResourceAttributesEnvvar is the name of the envvar that includes additional
 | 
					 | 
				
			||||||
	// resource attributes for OTEL.
 | 
					 | 
				
			||||||
	ResourceAttributesEnvvar = "OTEL_RESOURCE_ATTRIBUTES"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// errPluginNotFound is the error returned when a plugin could not be found.
 | 
					 | 
				
			||||||
type errPluginNotFound string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (errPluginNotFound) NotFound() {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (e errPluginNotFound) Error() string {
 | 
					 | 
				
			||||||
	return "Error: No such CLI plugin: " + string(e)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type notFound interface{ NotFound() }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsNotFound is true if the given error is due to a plugin not being found.
 | 
					 | 
				
			||||||
func IsNotFound(err error) bool {
 | 
					 | 
				
			||||||
	if e, ok := err.(*pluginError); ok {
 | 
					 | 
				
			||||||
		err = e.Cause()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	_, ok := err.(notFound)
 | 
					 | 
				
			||||||
	return ok
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// getPluginDirs returns the platform-specific locations to search for plugins
 | 
					 | 
				
			||||||
// in order of preference.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Plugin-discovery is performed in the following order of preference:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// 1. The "cli-plugins" directory inside the CLIs [config.Path] (usually "~/.docker/cli-plugins").
 | 
					 | 
				
			||||||
// 2. Additional plugin directories as configured through [ConfigFile.CLIPluginsExtraDirs].
 | 
					 | 
				
			||||||
// 3. Platform-specific defaultSystemPluginDirs.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs
 | 
					 | 
				
			||||||
func getPluginDirs(cfg *configfile.ConfigFile) ([]string, error) {
 | 
					 | 
				
			||||||
	var pluginDirs []string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if cfg != nil {
 | 
					 | 
				
			||||||
		pluginDirs = append(pluginDirs, cfg.CLIPluginsExtraDirs...)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	pluginDir, err := config.Path("cli-plugins")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pluginDirs = append(pluginDirs, pluginDir)
 | 
					 | 
				
			||||||
	pluginDirs = append(pluginDirs, defaultSystemPluginDirs...)
 | 
					 | 
				
			||||||
	return pluginDirs, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func addPluginCandidatesFromDir(res map[string][]string, d string) {
 | 
					 | 
				
			||||||
	dentries, err := os.ReadDir(d)
 | 
					 | 
				
			||||||
	// Silently ignore any directories which we cannot list (e.g. due to
 | 
					 | 
				
			||||||
	// permissions or anything else) or which is not a directory
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, dentry := range dentries {
 | 
					 | 
				
			||||||
		switch dentry.Type() & os.ModeType {
 | 
					 | 
				
			||||||
		case 0, os.ModeSymlink:
 | 
					 | 
				
			||||||
			// Regular file or symlink, keep going
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			// Something else, ignore.
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		name := dentry.Name()
 | 
					 | 
				
			||||||
		if !strings.HasPrefix(name, NamePrefix) {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		name = strings.TrimPrefix(name, NamePrefix)
 | 
					 | 
				
			||||||
		var err error
 | 
					 | 
				
			||||||
		if name, err = trimExeSuffix(name); err != nil {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		res[name] = append(res[name], filepath.Join(d, dentry.Name()))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// listPluginCandidates returns a map from plugin name to the list of (unvalidated) Candidates. The list is in descending order of priority.
 | 
					 | 
				
			||||||
func listPluginCandidates(dirs []string) map[string][]string {
 | 
					 | 
				
			||||||
	result := make(map[string][]string)
 | 
					 | 
				
			||||||
	for _, d := range dirs {
 | 
					 | 
				
			||||||
		addPluginCandidatesFromDir(result, d)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return result
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GetPlugin returns a plugin on the system by its name
 | 
					 | 
				
			||||||
func GetPlugin(name string, dockerCli command.Cli, rootcmd *cobra.Command) (*Plugin, error) {
 | 
					 | 
				
			||||||
	pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	candidates := listPluginCandidates(pluginDirs)
 | 
					 | 
				
			||||||
	if paths, ok := candidates[name]; ok {
 | 
					 | 
				
			||||||
		if len(paths) == 0 {
 | 
					 | 
				
			||||||
			return nil, errPluginNotFound(name)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		c := &candidate{paths[0]}
 | 
					 | 
				
			||||||
		p, err := newPlugin(c, rootcmd.Commands())
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !IsNotFound(p.Err) {
 | 
					 | 
				
			||||||
			p.ShadowedPaths = paths[1:]
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return &p, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil, errPluginNotFound(name)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ListPlugins produces a list of the plugins available on the system
 | 
					 | 
				
			||||||
func ListPlugins(dockerCli command.Cli, rootcmd *cobra.Command) ([]Plugin, error) {
 | 
					 | 
				
			||||||
	pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	candidates := listPluginCandidates(pluginDirs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var plugins []Plugin
 | 
					 | 
				
			||||||
	var mu sync.Mutex
 | 
					 | 
				
			||||||
	eg, _ := errgroup.WithContext(context.TODO())
 | 
					 | 
				
			||||||
	cmds := rootcmd.Commands()
 | 
					 | 
				
			||||||
	for _, paths := range candidates {
 | 
					 | 
				
			||||||
		func(paths []string) {
 | 
					 | 
				
			||||||
			eg.Go(func() error {
 | 
					 | 
				
			||||||
				if len(paths) == 0 {
 | 
					 | 
				
			||||||
					return nil
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				c := &candidate{paths[0]}
 | 
					 | 
				
			||||||
				p, err := newPlugin(c, cmds)
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					return err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if !IsNotFound(p.Err) {
 | 
					 | 
				
			||||||
					p.ShadowedPaths = paths[1:]
 | 
					 | 
				
			||||||
					mu.Lock()
 | 
					 | 
				
			||||||
					defer mu.Unlock()
 | 
					 | 
				
			||||||
					plugins = append(plugins, p)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return nil
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
		}(paths)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err := eg.Wait(); err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sort.Slice(plugins, func(i, j int) bool {
 | 
					 | 
				
			||||||
		return sortorder.NaturalLess(plugins[i].Name, plugins[j].Name)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return plugins, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// PluginRunCommand returns an "os/exec".Cmd which when .Run() will execute the named plugin.
 | 
					 | 
				
			||||||
// The rootcmd argument is referenced to determine the set of builtin commands in order to detect conficts.
 | 
					 | 
				
			||||||
// The error returned satisfies the IsNotFound() predicate if no plugin was found or if the first candidate plugin was invalid somehow.
 | 
					 | 
				
			||||||
func PluginRunCommand(dockerCli command.Cli, name string, rootcmd *cobra.Command) (*exec.Cmd, error) {
 | 
					 | 
				
			||||||
	// This uses the full original args, not the args which may
 | 
					 | 
				
			||||||
	// have been provided by cobra to our caller. This is because
 | 
					 | 
				
			||||||
	// they lack e.g. global options which we must propagate here.
 | 
					 | 
				
			||||||
	args := os.Args[1:]
 | 
					 | 
				
			||||||
	if !pluginNameRe.MatchString(name) {
 | 
					 | 
				
			||||||
		// We treat this as "not found" so that callers will
 | 
					 | 
				
			||||||
		// fallback to their "invalid" command path.
 | 
					 | 
				
			||||||
		return nil, errPluginNotFound(name)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	exename := addExeSuffix(NamePrefix + name)
 | 
					 | 
				
			||||||
	pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, d := range pluginDirs {
 | 
					 | 
				
			||||||
		path := filepath.Join(d, exename)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// We stat here rather than letting the exec tell us
 | 
					 | 
				
			||||||
		// ENOENT because the latter does not distinguish a
 | 
					 | 
				
			||||||
		// file not existing from its dynamic loader or one of
 | 
					 | 
				
			||||||
		// its libraries not existing.
 | 
					 | 
				
			||||||
		if _, err := os.Stat(path); os.IsNotExist(err) {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		c := &candidate{path: path}
 | 
					 | 
				
			||||||
		plugin, err := newPlugin(c, rootcmd.Commands())
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if plugin.Err != nil {
 | 
					 | 
				
			||||||
			// TODO: why are we not returning plugin.Err?
 | 
					 | 
				
			||||||
			return nil, errPluginNotFound(name)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		cmd := exec.Command(plugin.Path, args...) // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Using dockerCli.{In,Out,Err}() here results in a hang until something is input.
 | 
					 | 
				
			||||||
		// See: - https://github.com/golang/go/issues/10338
 | 
					 | 
				
			||||||
		//      - https://github.com/golang/go/commit/d000e8742a173aa0659584aa01b7ba2834ba28ab
 | 
					 | 
				
			||||||
		// os.Stdin is a *os.File which avoids this behaviour. We don't need the functionality
 | 
					 | 
				
			||||||
		// of the wrappers here anyway.
 | 
					 | 
				
			||||||
		cmd.Stdin = os.Stdin
 | 
					 | 
				
			||||||
		cmd.Stdout = os.Stdout
 | 
					 | 
				
			||||||
		cmd.Stderr = os.Stderr
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		cmd.Env = append(cmd.Environ(), ReexecEnvvar+"="+os.Args[0])
 | 
					 | 
				
			||||||
		cmd.Env = appendPluginResourceAttributesEnvvar(cmd.Env, rootcmd, plugin)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return cmd, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil, errPluginNotFound(name)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsPluginCommand checks if the given cmd is a plugin-stub.
 | 
					 | 
				
			||||||
func IsPluginCommand(cmd *cobra.Command) bool {
 | 
					 | 
				
			||||||
	return cmd.Annotations[CommandAnnotationPlugin] == "true"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										20
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,20 +0,0 @@
 | 
				
			|||||||
//go:build !windows
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// defaultSystemPluginDirs are the platform-specific locations to search
 | 
					 | 
				
			||||||
// for plugins in order of preference.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Plugin-discovery is performed in the following order of preference:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// 1. The "cli-plugins" directory inside the CLIs config-directory (usually "~/.docker/cli-plugins").
 | 
					 | 
				
			||||||
// 2. Additional plugin directories as configured through [ConfigFile.CLIPluginsExtraDirs].
 | 
					 | 
				
			||||||
// 3. Platform-specific defaultSystemPluginDirs (as defined below).
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs
 | 
					 | 
				
			||||||
var defaultSystemPluginDirs = []string{
 | 
					 | 
				
			||||||
	"/usr/local/lib/docker/cli-plugins",
 | 
					 | 
				
			||||||
	"/usr/local/libexec/docker/cli-plugins",
 | 
					 | 
				
			||||||
	"/usr/lib/docker/cli-plugins",
 | 
					 | 
				
			||||||
	"/usr/libexec/docker/cli-plugins",
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										21
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,21 +0,0 @@
 | 
				
			|||||||
package manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"path/filepath"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// defaultSystemPluginDirs are the platform-specific locations to search
 | 
					 | 
				
			||||||
// for plugins in order of preference.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Plugin-discovery is performed in the following order of preference:
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// 1. The "cli-plugins" directory inside the CLIs config-directory (usually "~/.docker/cli-plugins").
 | 
					 | 
				
			||||||
// 2. Additional plugin directories as configured through [ConfigFile.CLIPluginsExtraDirs].
 | 
					 | 
				
			||||||
// 3. Platform-specific defaultSystemPluginDirs (as defined below).
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs
 | 
					 | 
				
			||||||
var defaultSystemPluginDirs = []string{
 | 
					 | 
				
			||||||
	filepath.Join(os.Getenv("ProgramData"), "Docker", "cli-plugins"),
 | 
					 | 
				
			||||||
	filepath.Join(os.Getenv("ProgramFiles"), "Docker", "cli-plugins"),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										124
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/plugin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										124
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/plugin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,124 +0,0 @@
 | 
				
			|||||||
package manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"context"
 | 
					 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"os/exec"
 | 
					 | 
				
			||||||
	"path/filepath"
 | 
					 | 
				
			||||||
	"regexp"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var pluginNameRe = regexp.MustCompile("^[a-z][a-z0-9]*$")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Plugin represents a potential plugin with all it's metadata.
 | 
					 | 
				
			||||||
type Plugin struct {
 | 
					 | 
				
			||||||
	Metadata
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Name string `json:",omitempty"`
 | 
					 | 
				
			||||||
	Path string `json:",omitempty"`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Err is non-nil if the plugin failed one of the candidate tests.
 | 
					 | 
				
			||||||
	Err error `json:",omitempty"`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// ShadowedPaths contains the paths of any other plugins which this plugin takes precedence over.
 | 
					 | 
				
			||||||
	ShadowedPaths []string `json:",omitempty"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// newPlugin determines if the given candidate is valid and returns a
 | 
					 | 
				
			||||||
// Plugin.  If the candidate fails one of the tests then `Plugin.Err`
 | 
					 | 
				
			||||||
// is set, and is always a `pluginError`, but the `Plugin` is still
 | 
					 | 
				
			||||||
// returned with no error. An error is only returned due to a
 | 
					 | 
				
			||||||
// non-recoverable error.
 | 
					 | 
				
			||||||
func newPlugin(c Candidate, cmds []*cobra.Command) (Plugin, error) {
 | 
					 | 
				
			||||||
	path := c.Path()
 | 
					 | 
				
			||||||
	if path == "" {
 | 
					 | 
				
			||||||
		return Plugin{}, errors.New("plugin candidate path cannot be empty")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// The candidate listing process should have skipped anything
 | 
					 | 
				
			||||||
	// which would fail here, so there are all real errors.
 | 
					 | 
				
			||||||
	fullname := filepath.Base(path)
 | 
					 | 
				
			||||||
	if fullname == "." {
 | 
					 | 
				
			||||||
		return Plugin{}, errors.Errorf("unable to determine basename of plugin candidate %q", path)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var err error
 | 
					 | 
				
			||||||
	if fullname, err = trimExeSuffix(fullname); err != nil {
 | 
					 | 
				
			||||||
		return Plugin{}, errors.Wrapf(err, "plugin candidate %q", path)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !strings.HasPrefix(fullname, NamePrefix) {
 | 
					 | 
				
			||||||
		return Plugin{}, errors.Errorf("plugin candidate %q: does not have %q prefix", path, NamePrefix)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	p := Plugin{
 | 
					 | 
				
			||||||
		Name: strings.TrimPrefix(fullname, NamePrefix),
 | 
					 | 
				
			||||||
		Path: path,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Now apply the candidate tests, so these update p.Err.
 | 
					 | 
				
			||||||
	if !pluginNameRe.MatchString(p.Name) {
 | 
					 | 
				
			||||||
		p.Err = NewPluginError("plugin candidate %q did not match %q", p.Name, pluginNameRe.String())
 | 
					 | 
				
			||||||
		return p, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, cmd := range cmds {
 | 
					 | 
				
			||||||
		// Ignore conflicts with commands which are
 | 
					 | 
				
			||||||
		// just plugin stubs (i.e. from a previous
 | 
					 | 
				
			||||||
		// call to AddPluginCommandStubs).
 | 
					 | 
				
			||||||
		if IsPluginCommand(cmd) {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if cmd.Name() == p.Name {
 | 
					 | 
				
			||||||
			p.Err = NewPluginError("plugin %q duplicates builtin command", p.Name)
 | 
					 | 
				
			||||||
			return p, nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if cmd.HasAlias(p.Name) {
 | 
					 | 
				
			||||||
			p.Err = NewPluginError("plugin %q duplicates an alias of builtin command %q", p.Name, cmd.Name())
 | 
					 | 
				
			||||||
			return p, nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// We are supposed to check for relevant execute permissions here. Instead we rely on an attempt to execute.
 | 
					 | 
				
			||||||
	meta, err := c.Metadata()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		p.Err = wrapAsPluginError(err, "failed to fetch metadata")
 | 
					 | 
				
			||||||
		return p, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := json.Unmarshal(meta, &p.Metadata); err != nil {
 | 
					 | 
				
			||||||
		p.Err = wrapAsPluginError(err, "invalid metadata")
 | 
					 | 
				
			||||||
		return p, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if p.Metadata.SchemaVersion != "0.1.0" {
 | 
					 | 
				
			||||||
		p.Err = NewPluginError("plugin SchemaVersion %q is not valid, must be 0.1.0", p.Metadata.SchemaVersion)
 | 
					 | 
				
			||||||
		return p, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if p.Metadata.Vendor == "" {
 | 
					 | 
				
			||||||
		p.Err = NewPluginError("plugin metadata does not define a vendor")
 | 
					 | 
				
			||||||
		return p, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return p, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// RunHook executes the plugin's hooks command
 | 
					 | 
				
			||||||
// and returns its unprocessed output.
 | 
					 | 
				
			||||||
func (p *Plugin) RunHook(ctx context.Context, hookData HookPluginData) ([]byte, error) {
 | 
					 | 
				
			||||||
	hDataBytes, err := json.Marshal(hookData)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, wrapAsPluginError(err, "failed to marshall hook data")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pCmd := exec.CommandContext(ctx, p.Path, p.Name, HookSubcommandName, string(hDataBytes)) // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
 | 
					 | 
				
			||||||
	pCmd.Env = os.Environ()
 | 
					 | 
				
			||||||
	pCmd.Env = append(pCmd.Env, ReexecEnvvar+"="+os.Args[0])
 | 
					 | 
				
			||||||
	hookCmdOutput, err := pCmd.Output()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, wrapAsPluginError(err, "failed to execute plugin hook subcommand")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return hookCmdOutput, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										11
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/suffix_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/suffix_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,11 +0,0 @@
 | 
				
			|||||||
//go:build !windows
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func trimExeSuffix(s string) (string, error) {
 | 
					 | 
				
			||||||
	return s, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func addExeSuffix(s string) string {
 | 
					 | 
				
			||||||
	return s
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										26
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/suffix_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/suffix_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,26 +0,0 @@
 | 
				
			|||||||
package manager
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"path/filepath"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// This is made slightly more complex due to needing to be case insensitive.
 | 
					 | 
				
			||||||
func trimExeSuffix(s string) (string, error) {
 | 
					 | 
				
			||||||
	ext := filepath.Ext(s)
 | 
					 | 
				
			||||||
	if ext == "" {
 | 
					 | 
				
			||||||
		return "", errors.Errorf("path %q lacks required file extension", s)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	exe := ".exe"
 | 
					 | 
				
			||||||
	if !strings.EqualFold(ext, exe) {
 | 
					 | 
				
			||||||
		return "", errors.Errorf("path %q lacks required %q suffix", s, exe)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return strings.TrimSuffix(s, ext), nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func addExeSuffix(s string) string {
 | 
					 | 
				
			||||||
	return s + ".exe"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										28
									
								
								vendor/github.com/docker/cli/cli-plugins/metadata/annotations.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/docker/cli/cli-plugins/metadata/annotations.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					package metadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						// CommandAnnotationPlugin is added to every stub command added by
 | 
				
			||||||
 | 
						// AddPluginCommandStubs with the value "true" and so can be
 | 
				
			||||||
 | 
						// used to distinguish plugin stubs from regular commands.
 | 
				
			||||||
 | 
						CommandAnnotationPlugin = "com.docker.cli.plugin"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// CommandAnnotationPluginVendor is added to every stub command
 | 
				
			||||||
 | 
						// added by AddPluginCommandStubs and contains the vendor of
 | 
				
			||||||
 | 
						// that plugin.
 | 
				
			||||||
 | 
						CommandAnnotationPluginVendor = "com.docker.cli.plugin.vendor"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// CommandAnnotationPluginVersion is added to every stub command
 | 
				
			||||||
 | 
						// added by AddPluginCommandStubs and contains the version of
 | 
				
			||||||
 | 
						// that plugin.
 | 
				
			||||||
 | 
						CommandAnnotationPluginVersion = "com.docker.cli.plugin.version"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// CommandAnnotationPluginInvalid is added to any stub command
 | 
				
			||||||
 | 
						// added by AddPluginCommandStubs for an invalid command (that
 | 
				
			||||||
 | 
						// is, one which failed it's candidate test) and contains the
 | 
				
			||||||
 | 
						// reason for the failure.
 | 
				
			||||||
 | 
						CommandAnnotationPluginInvalid = "com.docker.cli.plugin-invalid"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// CommandAnnotationPluginCommandPath is added to overwrite the
 | 
				
			||||||
 | 
						// command path for a plugin invocation.
 | 
				
			||||||
 | 
						CommandAnnotationPluginCommandPath = "com.docker.cli.plugin.command_path"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package manager
 | 
					package metadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	// NamePrefix is the prefix required on all plugin binary names
 | 
						// NamePrefix is the prefix required on all plugin binary names
 | 
				
			||||||
@@ -13,6 +13,12 @@ const (
 | 
				
			|||||||
	// which must be implemented by plugins declaring support
 | 
						// which must be implemented by plugins declaring support
 | 
				
			||||||
	// for hooks in their metadata.
 | 
						// for hooks in their metadata.
 | 
				
			||||||
	HookSubcommandName = "docker-cli-plugin-hooks"
 | 
						HookSubcommandName = "docker-cli-plugin-hooks"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ReexecEnvvar is the name of an ennvar which is set to the command
 | 
				
			||||||
 | 
						// used to originally invoke the docker CLI when executing a
 | 
				
			||||||
 | 
						// plugin. Assuming $PATH and $CWD remain unchanged this should allow
 | 
				
			||||||
 | 
						// the plugin to re-execute the original CLI.
 | 
				
			||||||
 | 
						ReexecEnvvar = "DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Metadata provided by the plugin.
 | 
					// Metadata provided by the plugin.
 | 
				
			||||||
							
								
								
									
										20
									
								
								vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -9,7 +9,7 @@ import (
 | 
				
			|||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/cli/cli"
 | 
						"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/socket"
 | 
						"github.com/docker/cli/cli-plugins/socket"
 | 
				
			||||||
	"github.com/docker/cli/cli/command"
 | 
						"github.com/docker/cli/cli/command"
 | 
				
			||||||
	"github.com/docker/cli/cli/connhelper"
 | 
						"github.com/docker/cli/cli/connhelper"
 | 
				
			||||||
@@ -30,7 +30,7 @@ import (
 | 
				
			|||||||
var PersistentPreRunE func(*cobra.Command, []string) error
 | 
					var PersistentPreRunE func(*cobra.Command, []string) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RunPlugin executes the specified plugin command
 | 
					// RunPlugin executes the specified plugin command
 | 
				
			||||||
func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager.Metadata) error {
 | 
					func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta metadata.Metadata) error {
 | 
				
			||||||
	tcmd := newPluginCommand(dockerCli, plugin, meta)
 | 
						tcmd := newPluginCommand(dockerCli, plugin, meta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var persistentPreRunOnce sync.Once
 | 
						var persistentPreRunOnce sync.Once
 | 
				
			||||||
@@ -81,7 +81,7 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Run is the top-level entry point to the CLI plugin framework. It should be called from your plugin's `main()` function.
 | 
					// Run is the top-level entry point to the CLI plugin framework. It should be called from your plugin's `main()` function.
 | 
				
			||||||
func Run(makeCmd func(command.Cli) *cobra.Command, meta manager.Metadata) {
 | 
					func Run(makeCmd func(command.Cli) *cobra.Command, meta metadata.Metadata) {
 | 
				
			||||||
	otel.SetErrorHandler(debug.OTELErrorHandler)
 | 
						otel.SetErrorHandler(debug.OTELErrorHandler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dockerCli, err := command.NewDockerCli()
 | 
						dockerCli, err := command.NewDockerCli()
 | 
				
			||||||
@@ -111,7 +111,7 @@ func Run(makeCmd func(command.Cli) *cobra.Command, meta manager.Metadata) {
 | 
				
			|||||||
func withPluginClientConn(name string) command.CLIOption {
 | 
					func withPluginClientConn(name string) command.CLIOption {
 | 
				
			||||||
	return command.WithInitializeClient(func(dockerCli *command.DockerCli) (client.APIClient, error) {
 | 
						return command.WithInitializeClient(func(dockerCli *command.DockerCli) (client.APIClient, error) {
 | 
				
			||||||
		cmd := "docker"
 | 
							cmd := "docker"
 | 
				
			||||||
		if x := os.Getenv(manager.ReexecEnvvar); x != "" {
 | 
							if x := os.Getenv(metadata.ReexecEnvvar); x != "" {
 | 
				
			||||||
			cmd = x
 | 
								cmd = x
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		var flags []string
 | 
							var flags []string
 | 
				
			||||||
@@ -140,9 +140,9 @@ func withPluginClientConn(name string) command.CLIOption {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager.Metadata) *cli.TopLevelCommand {
 | 
					func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta metadata.Metadata) *cli.TopLevelCommand {
 | 
				
			||||||
	name := plugin.Name()
 | 
						name := plugin.Name()
 | 
				
			||||||
	fullname := manager.NamePrefix + name
 | 
						fullname := metadata.NamePrefix + name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd := &cobra.Command{
 | 
						cmd := &cobra.Command{
 | 
				
			||||||
		Use:           fmt.Sprintf("docker [OPTIONS] %s [ARG...]", name),
 | 
							Use:           fmt.Sprintf("docker [OPTIONS] %s [ARG...]", name),
 | 
				
			||||||
@@ -177,12 +177,12 @@ func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta
 | 
				
			|||||||
	return cli.NewTopLevelCommand(cmd, dockerCli, opts, cmd.Flags())
 | 
						return cli.NewTopLevelCommand(cmd, dockerCli, opts, cmd.Flags())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newMetadataSubcommand(plugin *cobra.Command, meta manager.Metadata) *cobra.Command {
 | 
					func newMetadataSubcommand(plugin *cobra.Command, meta metadata.Metadata) *cobra.Command {
 | 
				
			||||||
	if meta.ShortDescription == "" {
 | 
						if meta.ShortDescription == "" {
 | 
				
			||||||
		meta.ShortDescription = plugin.Short
 | 
							meta.ShortDescription = plugin.Short
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cmd := &cobra.Command{
 | 
						cmd := &cobra.Command{
 | 
				
			||||||
		Use:    manager.MetadataSubcommandName,
 | 
							Use:    metadata.MetadataSubcommandName,
 | 
				
			||||||
		Hidden: true,
 | 
							Hidden: true,
 | 
				
			||||||
		// Suppress the global/parent PersistentPreRunE, which
 | 
							// Suppress the global/parent PersistentPreRunE, which
 | 
				
			||||||
		// needlessly initializes the client and tries to
 | 
							// needlessly initializes the client and tries to
 | 
				
			||||||
@@ -200,8 +200,8 @@ func newMetadataSubcommand(plugin *cobra.Command, meta manager.Metadata) *cobra.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// RunningStandalone tells a CLI plugin it is run standalone by direct execution
 | 
					// RunningStandalone tells a CLI plugin it is run standalone by direct execution
 | 
				
			||||||
func RunningStandalone() bool {
 | 
					func RunningStandalone() bool {
 | 
				
			||||||
	if os.Getenv(manager.ReexecEnvvar) != "" {
 | 
						if os.Getenv(metadata.ReexecEnvvar) != "" {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName
 | 
						return len(os.Args) < 2 || os.Args[1] != metadata.MetadataSubcommandName
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								vendor/github.com/docker/cli/cli/cobra.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/docker/cli/cli/cobra.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -3,15 +3,12 @@ package cli
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
					 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pluginmanager "github.com/docker/cli/cli-plugins/manager"
 | 
						"github.com/docker/cli/cli-plugins/metadata"
 | 
				
			||||||
	"github.com/docker/cli/cli/command"
 | 
						"github.com/docker/cli/cli/command"
 | 
				
			||||||
	cliflags "github.com/docker/cli/cli/flags"
 | 
						cliflags "github.com/docker/cli/cli/flags"
 | 
				
			||||||
	"github.com/docker/docker/pkg/homedir"
 | 
					 | 
				
			||||||
	"github.com/docker/docker/registry"
 | 
					 | 
				
			||||||
	"github.com/fvbommel/sortorder"
 | 
						"github.com/fvbommel/sortorder"
 | 
				
			||||||
	"github.com/moby/term"
 | 
						"github.com/moby/term"
 | 
				
			||||||
	"github.com/morikuni/aec"
 | 
						"github.com/morikuni/aec"
 | 
				
			||||||
@@ -62,13 +59,6 @@ func setupCommonRootCommand(rootCmd *cobra.Command) (*cliflags.ClientOptions, *c
 | 
				
			|||||||
		"docs.code-delimiter": `"`, // https://github.com/docker/cli-docs-tool/blob/77abede22166eaea4af7335096bdcedd043f5b19/annotation/annotation.go#L20-L22
 | 
							"docs.code-delimiter": `"`, // https://github.com/docker/cli-docs-tool/blob/77abede22166eaea4af7335096bdcedd043f5b19/annotation/annotation.go#L20-L22
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Configure registry.CertsDir() when running in rootless-mode
 | 
					 | 
				
			||||||
	if os.Getenv("ROOTLESSKIT_STATE_DIR") != "" {
 | 
					 | 
				
			||||||
		if configHome, err := homedir.GetConfigHome(); err == nil {
 | 
					 | 
				
			||||||
			registry.SetCertsDir(filepath.Join(configHome, "docker/certs.d"))
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return opts, helpCommand
 | 
						return opts, helpCommand
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -252,7 +242,7 @@ func hasAdditionalHelp(cmd *cobra.Command) bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func isPlugin(cmd *cobra.Command) bool {
 | 
					func isPlugin(cmd *cobra.Command) bool {
 | 
				
			||||||
	return pluginmanager.IsPluginCommand(cmd)
 | 
						return cmd.Annotations[metadata.CommandAnnotationPlugin] == "true"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func hasAliases(cmd *cobra.Command) bool {
 | 
					func hasAliases(cmd *cobra.Command) bool {
 | 
				
			||||||
@@ -356,9 +346,9 @@ func decoratedName(cmd *cobra.Command) string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func vendorAndVersion(cmd *cobra.Command) string {
 | 
					func vendorAndVersion(cmd *cobra.Command) string {
 | 
				
			||||||
	if vendor, ok := cmd.Annotations[pluginmanager.CommandAnnotationPluginVendor]; ok && isPlugin(cmd) {
 | 
						if vendor, ok := cmd.Annotations[metadata.CommandAnnotationPluginVendor]; ok && isPlugin(cmd) {
 | 
				
			||||||
		version := ""
 | 
							version := ""
 | 
				
			||||||
		if v, ok := cmd.Annotations[pluginmanager.CommandAnnotationPluginVersion]; ok && v != "" {
 | 
							if v, ok := cmd.Annotations[metadata.CommandAnnotationPluginVersion]; ok && v != "" {
 | 
				
			||||||
			version = ", " + v
 | 
								version = ", " + v
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return fmt.Sprintf("(%s%s)", vendor, version)
 | 
							return fmt.Sprintf("(%s%s)", vendor, version)
 | 
				
			||||||
@@ -417,7 +407,7 @@ func invalidPlugins(cmd *cobra.Command) []*cobra.Command {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func invalidPluginReason(cmd *cobra.Command) string {
 | 
					func invalidPluginReason(cmd *cobra.Command) string {
 | 
				
			||||||
	return cmd.Annotations[pluginmanager.CommandAnnotationPluginInvalid]
 | 
						return cmd.Annotations[metadata.CommandAnnotationPluginInvalid]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const usageTemplate = `Usage:
 | 
					const usageTemplate = `Usage:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										59
									
								
								vendor/github.com/docker/cli/cli/command/cli.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										59
									
								
								vendor/github.com/docker/cli/cli/command/cli.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -8,7 +8,6 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
					 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@@ -21,21 +20,15 @@ import (
 | 
				
			|||||||
	"github.com/docker/cli/cli/context/store"
 | 
						"github.com/docker/cli/cli/context/store"
 | 
				
			||||||
	"github.com/docker/cli/cli/debug"
 | 
						"github.com/docker/cli/cli/debug"
 | 
				
			||||||
	cliflags "github.com/docker/cli/cli/flags"
 | 
						cliflags "github.com/docker/cli/cli/flags"
 | 
				
			||||||
	manifeststore "github.com/docker/cli/cli/manifest/store"
 | 
					 | 
				
			||||||
	registryclient "github.com/docker/cli/cli/registry/client"
 | 
					 | 
				
			||||||
	"github.com/docker/cli/cli/streams"
 | 
						"github.com/docker/cli/cli/streams"
 | 
				
			||||||
	"github.com/docker/cli/cli/trust"
 | 
					 | 
				
			||||||
	"github.com/docker/cli/cli/version"
 | 
						"github.com/docker/cli/cli/version"
 | 
				
			||||||
	dopts "github.com/docker/cli/opts"
 | 
						dopts "github.com/docker/cli/opts"
 | 
				
			||||||
	"github.com/docker/docker/api"
 | 
						"github.com/docker/docker/api"
 | 
				
			||||||
	"github.com/docker/docker/api/types"
 | 
						"github.com/docker/docker/api/types"
 | 
				
			||||||
	"github.com/docker/docker/api/types/registry"
 | 
					 | 
				
			||||||
	"github.com/docker/docker/api/types/swarm"
 | 
						"github.com/docker/docker/api/types/swarm"
 | 
				
			||||||
	"github.com/docker/docker/client"
 | 
						"github.com/docker/docker/client"
 | 
				
			||||||
	"github.com/docker/go-connections/tlsconfig"
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
						"github.com/pkg/errors"
 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
	notaryclient "github.com/theupdateframework/notary/client"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const defaultInitTimeout = 2 * time.Second
 | 
					const defaultInitTimeout = 2 * time.Second
 | 
				
			||||||
@@ -53,19 +46,18 @@ type Cli interface {
 | 
				
			|||||||
	Streams
 | 
						Streams
 | 
				
			||||||
	SetIn(in *streams.In)
 | 
						SetIn(in *streams.In)
 | 
				
			||||||
	Apply(ops ...CLIOption) error
 | 
						Apply(ops ...CLIOption) error
 | 
				
			||||||
	ConfigFile() *configfile.ConfigFile
 | 
						config.Provider
 | 
				
			||||||
	ServerInfo() ServerInfo
 | 
						ServerInfo() ServerInfo
 | 
				
			||||||
	NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error)
 | 
					 | 
				
			||||||
	DefaultVersion() string
 | 
						DefaultVersion() string
 | 
				
			||||||
	CurrentVersion() string
 | 
						CurrentVersion() string
 | 
				
			||||||
	ManifestStore() manifeststore.Store
 | 
					 | 
				
			||||||
	RegistryClient(bool) registryclient.RegistryClient
 | 
					 | 
				
			||||||
	ContentTrustEnabled() bool
 | 
						ContentTrustEnabled() bool
 | 
				
			||||||
	BuildKitEnabled() (bool, error)
 | 
						BuildKitEnabled() (bool, error)
 | 
				
			||||||
	ContextStore() store.Store
 | 
						ContextStore() store.Store
 | 
				
			||||||
	CurrentContext() string
 | 
						CurrentContext() string
 | 
				
			||||||
	DockerEndpoint() docker.Endpoint
 | 
						DockerEndpoint() docker.Endpoint
 | 
				
			||||||
	TelemetryClient
 | 
						TelemetryClient
 | 
				
			||||||
 | 
						DeprecatedNotaryClient
 | 
				
			||||||
 | 
						DeprecatedManifestClient
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DockerCli is an instance the docker command line client.
 | 
					// DockerCli is an instance the docker command line client.
 | 
				
			||||||
@@ -96,7 +88,7 @@ type DockerCli struct {
 | 
				
			|||||||
	enableGlobalMeter, enableGlobalTracer bool
 | 
						enableGlobalMeter, enableGlobalTracer bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DefaultVersion returns api.defaultVersion.
 | 
					// DefaultVersion returns [api.DefaultVersion].
 | 
				
			||||||
func (*DockerCli) DefaultVersion() string {
 | 
					func (*DockerCli) DefaultVersion() string {
 | 
				
			||||||
	return api.DefaultVersion
 | 
						return api.DefaultVersion
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -202,16 +194,16 @@ func (cli *DockerCli) BuildKitEnabled() (bool, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// HooksEnabled returns whether plugin hooks are enabled.
 | 
					// HooksEnabled returns whether plugin hooks are enabled.
 | 
				
			||||||
func (cli *DockerCli) HooksEnabled() bool {
 | 
					func (cli *DockerCli) HooksEnabled() bool {
 | 
				
			||||||
	// legacy support DOCKER_CLI_HINTS env var
 | 
						// use DOCKER_CLI_HOOKS env var value if set and not empty
 | 
				
			||||||
	if v := os.Getenv("DOCKER_CLI_HINTS"); v != "" {
 | 
						if v := os.Getenv("DOCKER_CLI_HOOKS"); v != "" {
 | 
				
			||||||
		enabled, err := strconv.ParseBool(v)
 | 
							enabled, err := strconv.ParseBool(v)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return false
 | 
								return false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return enabled
 | 
							return enabled
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// use DOCKER_CLI_HOOKS env var value if set and not empty
 | 
						// legacy support DOCKER_CLI_HINTS env var
 | 
				
			||||||
	if v := os.Getenv("DOCKER_CLI_HOOKS"); v != "" {
 | 
						if v := os.Getenv("DOCKER_CLI_HINTS"); v != "" {
 | 
				
			||||||
		enabled, err := strconv.ParseBool(v)
 | 
							enabled, err := strconv.ParseBool(v)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return false
 | 
								return false
 | 
				
			||||||
@@ -230,21 +222,6 @@ func (cli *DockerCli) HooksEnabled() bool {
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ManifestStore returns a store for local manifests
 | 
					 | 
				
			||||||
func (*DockerCli) ManifestStore() manifeststore.Store {
 | 
					 | 
				
			||||||
	// TODO: support override default location from config file
 | 
					 | 
				
			||||||
	return manifeststore.NewStore(filepath.Join(config.Dir(), "manifests"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// RegistryClient returns a client for communicating with a Docker distribution
 | 
					 | 
				
			||||||
// registry
 | 
					 | 
				
			||||||
func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.RegistryClient {
 | 
					 | 
				
			||||||
	resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig {
 | 
					 | 
				
			||||||
		return ResolveAuthConfig(cli.ConfigFile(), index)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return registryclient.NewRegistryClient(resolver, UserAgent(), allowInsecure)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// WithInitializeClient is passed to DockerCli.Initialize by callers who wish to set a particular API Client for use by the CLI.
 | 
					// WithInitializeClient is passed to DockerCli.Initialize by callers who wish to set a particular API Client for use by the CLI.
 | 
				
			||||||
func WithInitializeClient(makeClient func(dockerCli *DockerCli) (client.APIClient, error)) CLIOption {
 | 
					func WithInitializeClient(makeClient func(dockerCli *DockerCli) (client.APIClient, error)) CLIOption {
 | 
				
			||||||
	return func(dockerCli *DockerCli) error {
 | 
						return func(dockerCli *DockerCli) error {
 | 
				
			||||||
@@ -292,6 +269,7 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption)
 | 
				
			|||||||
	if cli.enableGlobalTracer {
 | 
						if cli.enableGlobalTracer {
 | 
				
			||||||
		cli.createGlobalTracerProvider(cli.baseCtx)
 | 
							cli.createGlobalTracerProvider(cli.baseCtx)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						filterResourceAttributesEnvvar()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -345,7 +323,10 @@ func resolveDockerEndpoint(s store.Reader, contextName string) (docker.Endpoint,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Resolve the Docker endpoint for the default context (based on config, env vars and CLI flags)
 | 
					// Resolve the Docker endpoint for the default context (based on config, env vars and CLI flags)
 | 
				
			||||||
func resolveDefaultDockerEndpoint(opts *cliflags.ClientOptions) (docker.Endpoint, error) {
 | 
					func resolveDefaultDockerEndpoint(opts *cliflags.ClientOptions) (docker.Endpoint, error) {
 | 
				
			||||||
	host, err := getServerHost(opts.Hosts, opts.TLSOptions)
 | 
						// defaultToTLS determines whether we should use a TLS host as default
 | 
				
			||||||
 | 
						// if nothing was configured by the user.
 | 
				
			||||||
 | 
						defaultToTLS := opts.TLSOptions != nil
 | 
				
			||||||
 | 
						host, err := getServerHost(opts.Hosts, defaultToTLS)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return docker.Endpoint{}, err
 | 
							return docker.Endpoint{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -403,11 +384,6 @@ func (cli *DockerCli) initializeFromClient() {
 | 
				
			|||||||
	cli.client.NegotiateAPIVersionPing(ping)
 | 
						cli.client.NegotiateAPIVersionPing(ping)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NotaryClient provides a Notary Repository to interact with signed metadata for an image
 | 
					 | 
				
			||||||
func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) {
 | 
					 | 
				
			||||||
	return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ContextStore returns the ContextStore
 | 
					// ContextStore returns the ContextStore
 | 
				
			||||||
func (cli *DockerCli) ContextStore() store.Store {
 | 
					func (cli *DockerCli) ContextStore() store.Store {
 | 
				
			||||||
	return cli.contextStore
 | 
						return cli.contextStore
 | 
				
			||||||
@@ -553,18 +529,15 @@ func NewDockerCli(ops ...CLIOption) (*DockerCli, error) {
 | 
				
			|||||||
	return cli, nil
 | 
						return cli, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (string, error) {
 | 
					func getServerHost(hosts []string, defaultToTLS bool) (string, error) {
 | 
				
			||||||
	var host string
 | 
					 | 
				
			||||||
	switch len(hosts) {
 | 
						switch len(hosts) {
 | 
				
			||||||
	case 0:
 | 
						case 0:
 | 
				
			||||||
		host = os.Getenv(client.EnvOverrideHost)
 | 
							return dopts.ParseHost(defaultToTLS, os.Getenv(client.EnvOverrideHost))
 | 
				
			||||||
	case 1:
 | 
						case 1:
 | 
				
			||||||
		host = hosts[0]
 | 
							return dopts.ParseHost(defaultToTLS, hosts[0])
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return "", errors.New("Specify only one -H")
 | 
							return "", errors.New("Specify only one -H")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return dopts.ParseHost(tlsOptions != nil, host)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UserAgent returns the user agent string used for making API requests
 | 
					// UserAgent returns the user agent string used for making API requests
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										56
									
								
								vendor/github.com/docker/cli/cli/command/cli_deprecated.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/docker/cli/cli/command/cli_deprecated.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					package command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/docker/cli/cli/config"
 | 
				
			||||||
 | 
						manifeststore "github.com/docker/cli/cli/manifest/store"
 | 
				
			||||||
 | 
						registryclient "github.com/docker/cli/cli/registry/client"
 | 
				
			||||||
 | 
						"github.com/docker/cli/cli/trust"
 | 
				
			||||||
 | 
						"github.com/docker/docker/api/types/registry"
 | 
				
			||||||
 | 
						notaryclient "github.com/theupdateframework/notary/client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DeprecatedNotaryClient interface {
 | 
				
			||||||
 | 
						// NotaryClient provides a Notary Repository to interact with signed metadata for an image
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Deprecated: use [trust.GetNotaryRepository] instead. This method is no longer used and will be removed in the next release.
 | 
				
			||||||
 | 
						NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DeprecatedManifestClient interface {
 | 
				
			||||||
 | 
						// ManifestStore returns a store for local manifests
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Deprecated: use [manifeststore.NewStore] instead. This method is no longer used and will be removed in the next release.
 | 
				
			||||||
 | 
						ManifestStore() manifeststore.Store
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// RegistryClient returns a client for communicating with a Docker distribution
 | 
				
			||||||
 | 
						// registry.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Deprecated: use [registryclient.NewRegistryClient]. This method is no longer used and will be removed in the next release.
 | 
				
			||||||
 | 
						RegistryClient(bool) registryclient.RegistryClient
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NotaryClient provides a Notary Repository to interact with signed metadata for an image
 | 
				
			||||||
 | 
					func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) {
 | 
				
			||||||
 | 
						return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ManifestStore returns a store for local manifests
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Deprecated: use [manifeststore.NewStore] instead. This method is no longer used and will be removed in the next release.
 | 
				
			||||||
 | 
					func (*DockerCli) ManifestStore() manifeststore.Store {
 | 
				
			||||||
 | 
						return manifeststore.NewStore(filepath.Join(config.Dir(), "manifests"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RegistryClient returns a client for communicating with a Docker distribution
 | 
				
			||||||
 | 
					// registry
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Deprecated: use [registryclient.NewRegistryClient]. This method is no longer used and will be removed in the next release.
 | 
				
			||||||
 | 
					func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.RegistryClient {
 | 
				
			||||||
 | 
						resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig {
 | 
				
			||||||
 | 
							return ResolveAuthConfig(cli.ConfigFile(), index)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return registryclient.NewRegistryClient(resolver, UserAgent(), allowInsecure)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								vendor/github.com/docker/cli/cli/command/formatter/displayutils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/docker/cli/cli/command/formatter/displayutils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,11 @@
 | 
				
			|||||||
 | 
					// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
 | 
				
			||||||
 | 
					//go:build go1.22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package formatter
 | 
					package formatter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"unicode/utf8"
 | 
						"unicode/utf8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"golang.org/x/text/width"
 | 
						"golang.org/x/text/width"
 | 
				
			||||||
@@ -59,3 +64,27 @@ func Ellipsis(s string, maxDisplayWidth int) string {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return s
 | 
						return s
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// capitalizeFirst capitalizes the first character of string
 | 
				
			||||||
 | 
					func capitalizeFirst(s string) string {
 | 
				
			||||||
 | 
						switch l := len(s); l {
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
 | 
							return s
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							return strings.ToLower(s)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return strings.ToUpper(string(s[0])) + strings.ToLower(s[1:])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PrettyPrint outputs arbitrary data for human formatted output by uppercasing the first letter.
 | 
				
			||||||
 | 
					func PrettyPrint(i any) string {
 | 
				
			||||||
 | 
						switch t := i.(type) {
 | 
				
			||||||
 | 
						case nil:
 | 
				
			||||||
 | 
							return "None"
 | 
				
			||||||
 | 
						case string:
 | 
				
			||||||
 | 
							return capitalizeFirst(t)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return capitalizeFirst(fmt.Sprintf("%s", t))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								vendor/github.com/docker/cli/cli/command/formatter/formatter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/docker/cli/cli/command/formatter/formatter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -76,9 +76,9 @@ func (c *Context) preFormat() {
 | 
				
			|||||||
func (c *Context) parseFormat() (*template.Template, error) {
 | 
					func (c *Context) parseFormat() (*template.Template, error) {
 | 
				
			||||||
	tmpl, err := templates.Parse(c.finalFormat)
 | 
						tmpl, err := templates.Parse(c.finalFormat)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return tmpl, errors.Wrap(err, "template parsing error")
 | 
							return nil, errors.Wrap(err, "template parsing error")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return tmpl, err
 | 
						return tmpl, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Context) postFormat(tmpl *template.Template, subContext SubContext) {
 | 
					func (c *Context) postFormat(tmpl *template.Template, subContext SubContext) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										51
									
								
								vendor/github.com/docker/cli/cli/command/telemetry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/docker/cli/cli/command/telemetry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,10 +4,11 @@ import (
 | 
				
			|||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/distribution/uuid"
 | 
						"github.com/google/uuid"
 | 
				
			||||||
	"go.opentelemetry.io/otel"
 | 
						"go.opentelemetry.io/otel"
 | 
				
			||||||
	"go.opentelemetry.io/otel/metric"
 | 
						"go.opentelemetry.io/otel/metric"
 | 
				
			||||||
	sdkmetric "go.opentelemetry.io/otel/sdk/metric"
 | 
						sdkmetric "go.opentelemetry.io/otel/sdk/metric"
 | 
				
			||||||
@@ -142,7 +143,7 @@ func defaultResourceOptions() []resource.Option {
 | 
				
			|||||||
			// of the CLI is its own instance. Without this, downstream
 | 
								// of the CLI is its own instance. Without this, downstream
 | 
				
			||||||
			// OTEL processors may think the same process is restarting
 | 
								// OTEL processors may think the same process is restarting
 | 
				
			||||||
			// continuously.
 | 
								// continuously.
 | 
				
			||||||
			semconv.ServiceInstanceID(uuid.Generate().String()),
 | 
								semconv.ServiceInstanceID(uuid.NewString()),
 | 
				
			||||||
		),
 | 
							),
 | 
				
			||||||
		resource.WithFromEnv(),
 | 
							resource.WithFromEnv(),
 | 
				
			||||||
		resource.WithTelemetrySDK(),
 | 
							resource.WithTelemetrySDK(),
 | 
				
			||||||
@@ -216,3 +217,49 @@ func (r *cliReader) ForceFlush(ctx context.Context) error {
 | 
				
			|||||||
func deltaTemporality(_ sdkmetric.InstrumentKind) metricdata.Temporality {
 | 
					func deltaTemporality(_ sdkmetric.InstrumentKind) metricdata.Temporality {
 | 
				
			||||||
	return metricdata.DeltaTemporality
 | 
						return metricdata.DeltaTemporality
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// resourceAttributesEnvVar is the name of the envvar that includes additional
 | 
				
			||||||
 | 
					// resource attributes for OTEL as defined in the [OpenTelemetry specification].
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// [OpenTelemetry specification]: https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration
 | 
				
			||||||
 | 
					const resourceAttributesEnvVar = "OTEL_RESOURCE_ATTRIBUTES"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func filterResourceAttributesEnvvar() {
 | 
				
			||||||
 | 
						if v := os.Getenv(resourceAttributesEnvVar); v != "" {
 | 
				
			||||||
 | 
							if filtered := filterResourceAttributes(v); filtered != "" {
 | 
				
			||||||
 | 
								_ = os.Setenv(resourceAttributesEnvVar, filtered)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								_ = os.Unsetenv(resourceAttributesEnvVar)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// dockerCLIAttributePrefix is the prefix for any docker cli OTEL attributes.
 | 
				
			||||||
 | 
					// When updating, make sure to also update the copy in cli-plugins/manager.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// TODO(thaJeztah): move telemetry-related code to an (internal) package to reduce dependency on cli/command in cli-plugins, which has too many imports.
 | 
				
			||||||
 | 
					const dockerCLIAttributePrefix = "docker.cli."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func filterResourceAttributes(s string) string {
 | 
				
			||||||
 | 
						if trimmed := strings.TrimSpace(s); trimmed == "" {
 | 
				
			||||||
 | 
							return trimmed
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pairs := strings.Split(s, ",")
 | 
				
			||||||
 | 
						elems := make([]string, 0, len(pairs))
 | 
				
			||||||
 | 
						for _, p := range pairs {
 | 
				
			||||||
 | 
							k, _, found := strings.Cut(p, "=")
 | 
				
			||||||
 | 
							if !found {
 | 
				
			||||||
 | 
								// Do not interact with invalid otel resources.
 | 
				
			||||||
 | 
								elems = append(elems, p)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Skip attributes that have our docker.cli prefix.
 | 
				
			||||||
 | 
							if strings.HasPrefix(k, dockerCLIAttributePrefix) {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							elems = append(elems, p)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return strings.Join(elems, ",")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										79
									
								
								vendor/github.com/docker/cli/cli/command/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/docker/cli/cli/command/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -13,10 +13,9 @@ import (
 | 
				
			|||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/docker/cli/cli/config"
 | 
				
			||||||
	"github.com/docker/cli/cli/streams"
 | 
						"github.com/docker/cli/cli/streams"
 | 
				
			||||||
	"github.com/docker/docker/api/types/filters"
 | 
						"github.com/docker/docker/api/types/filters"
 | 
				
			||||||
	mounttypes "github.com/docker/docker/api/types/mount"
 | 
					 | 
				
			||||||
	"github.com/docker/docker/api/types/versions"
 | 
					 | 
				
			||||||
	"github.com/docker/docker/errdefs"
 | 
						"github.com/docker/docker/errdefs"
 | 
				
			||||||
	"github.com/moby/sys/sequential"
 | 
						"github.com/moby/sys/sequential"
 | 
				
			||||||
	"github.com/moby/term"
 | 
						"github.com/moby/term"
 | 
				
			||||||
@@ -51,30 +50,6 @@ func CopyToFile(outfile string, r io.Reader) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// capitalizeFirst capitalizes the first character of string
 | 
					 | 
				
			||||||
func capitalizeFirst(s string) string {
 | 
					 | 
				
			||||||
	switch l := len(s); l {
 | 
					 | 
				
			||||||
	case 0:
 | 
					 | 
				
			||||||
		return s
 | 
					 | 
				
			||||||
	case 1:
 | 
					 | 
				
			||||||
		return strings.ToLower(s)
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return strings.ToUpper(string(s[0])) + strings.ToLower(s[1:])
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// PrettyPrint outputs arbitrary data for human formatted output by uppercasing the first letter.
 | 
					 | 
				
			||||||
func PrettyPrint(i any) string {
 | 
					 | 
				
			||||||
	switch t := i.(type) {
 | 
					 | 
				
			||||||
	case nil:
 | 
					 | 
				
			||||||
		return "None"
 | 
					 | 
				
			||||||
	case string:
 | 
					 | 
				
			||||||
		return capitalizeFirst(t)
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return capitalizeFirst(fmt.Sprintf("%s", t))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var ErrPromptTerminated = errdefs.Cancelled(errors.New("prompt terminated"))
 | 
					var ErrPromptTerminated = errdefs.Cancelled(errors.New("prompt terminated"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DisableInputEcho disables input echo on the provided streams.In.
 | 
					// DisableInputEcho disables input echo on the provided streams.In.
 | 
				
			||||||
@@ -166,11 +141,12 @@ func PromptForConfirmation(ctx context.Context, ins io.Reader, outs io.Writer, m
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PruneFilters returns consolidated prune filters obtained from config.json and cli
 | 
					// PruneFilters returns consolidated prune filters obtained from config.json and cli
 | 
				
			||||||
func PruneFilters(dockerCli Cli, pruneFilters filters.Args) filters.Args {
 | 
					func PruneFilters(dockerCLI config.Provider, pruneFilters filters.Args) filters.Args {
 | 
				
			||||||
	if dockerCli.ConfigFile() == nil {
 | 
						cfg := dockerCLI.ConfigFile()
 | 
				
			||||||
 | 
						if cfg == nil {
 | 
				
			||||||
		return pruneFilters
 | 
							return pruneFilters
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, f := range dockerCli.ConfigFile().PruneFilters {
 | 
						for _, f := range cfg.PruneFilters {
 | 
				
			||||||
		k, v, ok := strings.Cut(f, "=")
 | 
							k, v, ok := strings.Cut(f, "=")
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
@@ -239,48 +215,3 @@ func ValidateOutputPathFileMode(fileMode os.FileMode) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func stringSliceIndex(s, subs []string) int {
 | 
					 | 
				
			||||||
	j := 0
 | 
					 | 
				
			||||||
	if len(subs) > 0 {
 | 
					 | 
				
			||||||
		for i, x := range s {
 | 
					 | 
				
			||||||
			if j < len(subs) && subs[j] == x {
 | 
					 | 
				
			||||||
				j++
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				j = 0
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if len(subs) == j {
 | 
					 | 
				
			||||||
				return i + 1 - j
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return -1
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// StringSliceReplaceAt replaces the sub-slice find, with the sub-slice replace, in the string
 | 
					 | 
				
			||||||
// slice s, returning a new slice and a boolean indicating if the replacement happened.
 | 
					 | 
				
			||||||
// requireIdx is the index at which old needs to be found at (or -1 to disregard that).
 | 
					 | 
				
			||||||
func StringSliceReplaceAt(s, find, replace []string, requireIndex int) ([]string, bool) {
 | 
					 | 
				
			||||||
	idx := stringSliceIndex(s, find)
 | 
					 | 
				
			||||||
	if (requireIndex != -1 && requireIndex != idx) || idx == -1 {
 | 
					 | 
				
			||||||
		return s, false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	out := append([]string{}, s[:idx]...)
 | 
					 | 
				
			||||||
	out = append(out, replace...)
 | 
					 | 
				
			||||||
	out = append(out, s[idx+len(find):]...)
 | 
					 | 
				
			||||||
	return out, true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ValidateMountWithAPIVersion validates a mount with the server API version.
 | 
					 | 
				
			||||||
func ValidateMountWithAPIVersion(m mounttypes.Mount, serverAPIVersion string) error {
 | 
					 | 
				
			||||||
	if m.BindOptions != nil {
 | 
					 | 
				
			||||||
		if m.BindOptions.NonRecursive && versions.LessThan(serverAPIVersion, "1.40") {
 | 
					 | 
				
			||||||
			return errors.Errorf("bind-recursive=disabled requires API v1.40 or later")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		// ReadOnlyNonRecursive can be safely ignored when API < 1.44
 | 
					 | 
				
			||||||
		if m.BindOptions.ReadOnlyForceRecursive && versions.LessThan(serverAPIVersion, "1.44") {
 | 
					 | 
				
			||||||
			return errors.Errorf("bind-recursive=readonly requires API v1.44 or later")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								vendor/github.com/docker/cli/cli/config/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/docker/cli/cli/config/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -69,6 +69,11 @@ func getHomeDir() string {
 | 
				
			|||||||
	return home
 | 
						return home
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Provider defines an interface for providing the CLI config.
 | 
				
			||||||
 | 
					type Provider interface {
 | 
				
			||||||
 | 
						ConfigFile() *configfile.ConfigFile
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Dir returns the directory the configuration file is stored in
 | 
					// Dir returns the directory the configuration file is stored in
 | 
				
			||||||
func Dir() string {
 | 
					func Dir() string {
 | 
				
			||||||
	initConfigDir.Do(func() {
 | 
						initConfigDir.Do(func() {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										68
									
								
								vendor/github.com/docker/cli/cli/internal/jsonstream/display.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								vendor/github.com/docker/cli/cli/internal/jsonstream/display.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					package jsonstream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/docker/docker/pkg/jsonmessage"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type (
 | 
				
			||||||
 | 
						Stream       = jsonmessage.Stream
 | 
				
			||||||
 | 
						JSONMessage  = jsonmessage.JSONMessage
 | 
				
			||||||
 | 
						JSONError    = jsonmessage.JSONError
 | 
				
			||||||
 | 
						JSONProgress = jsonmessage.JSONProgress
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ctxReader struct {
 | 
				
			||||||
 | 
						err chan error
 | 
				
			||||||
 | 
						r   io.Reader
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *ctxReader) Read(p []byte) (n int, err error) {
 | 
				
			||||||
 | 
						select {
 | 
				
			||||||
 | 
						case err = <-r.err:
 | 
				
			||||||
 | 
							return 0, err
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return r.r.Read(p)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Options func(*options)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type options struct {
 | 
				
			||||||
 | 
						AuxCallback func(JSONMessage)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func WithAuxCallback(cb func(JSONMessage)) Options {
 | 
				
			||||||
 | 
						return func(o *options) {
 | 
				
			||||||
 | 
							o.AuxCallback = cb
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Display prints the JSON messages from the given reader to the given stream.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// It wraps the [jsonmessage.DisplayJSONMessagesStream] function to make it
 | 
				
			||||||
 | 
					// "context aware" and appropriately returns why the function was canceled.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// It returns an error if the context is canceled, but not if the input reader / stream is closed.
 | 
				
			||||||
 | 
					func Display(ctx context.Context, in io.Reader, stream Stream, opts ...Options) error {
 | 
				
			||||||
 | 
						if ctx.Err() != nil {
 | 
				
			||||||
 | 
							return ctx.Err()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reader := &ctxReader{err: make(chan error, 1), r: in}
 | 
				
			||||||
 | 
						stopFunc := context.AfterFunc(ctx, func() { reader.err <- ctx.Err() })
 | 
				
			||||||
 | 
						defer stopFunc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						o := options{}
 | 
				
			||||||
 | 
						for _, opt := range opts {
 | 
				
			||||||
 | 
							opt(&o)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := jsonmessage.DisplayJSONMessagesStream(reader, stream, stream.FD(), stream.IsTerminal(), o.AuxCallback); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ctx.Err()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								vendor/github.com/docker/cli/cli/registry/client/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/docker/cli/cli/registry/client/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -8,7 +8,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/distribution/reference"
 | 
						"github.com/distribution/reference"
 | 
				
			||||||
	manifesttypes "github.com/docker/cli/cli/manifest/types"
 | 
						manifesttypes "github.com/docker/cli/cli/manifest/types"
 | 
				
			||||||
	"github.com/docker/cli/cli/trust"
 | 
					 | 
				
			||||||
	"github.com/docker/distribution"
 | 
						"github.com/docker/distribution"
 | 
				
			||||||
	distributionclient "github.com/docker/distribution/registry/client"
 | 
						distributionclient "github.com/docker/distribution/registry/client"
 | 
				
			||||||
	registrytypes "github.com/docker/docker/api/types/registry"
 | 
						registrytypes "github.com/docker/docker/api/types/registry"
 | 
				
			||||||
@@ -38,12 +37,6 @@ func NewRegistryClient(resolver AuthConfigResolver, userAgent string, insecure b
 | 
				
			|||||||
// AuthConfigResolver returns Auth Configuration for an index
 | 
					// AuthConfigResolver returns Auth Configuration for an index
 | 
				
			||||||
type AuthConfigResolver func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig
 | 
					type AuthConfigResolver func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PutManifestOptions is the data sent to push a manifest
 | 
					 | 
				
			||||||
type PutManifestOptions struct {
 | 
					 | 
				
			||||||
	MediaType string
 | 
					 | 
				
			||||||
	Payload   []byte
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type client struct {
 | 
					type client struct {
 | 
				
			||||||
	authConfigResolver AuthConfigResolver
 | 
						authConfigResolver AuthConfigResolver
 | 
				
			||||||
	insecureRegistry   bool
 | 
						insecureRegistry   bool
 | 
				
			||||||
@@ -61,13 +54,13 @@ func (err ErrBlobCreated) Error() string {
 | 
				
			|||||||
		err.From, err.Target)
 | 
							err.From, err.Target)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrHTTPProto returned if attempting to use TLS with a non-TLS registry
 | 
					// httpProtoError returned if attempting to use TLS with a non-TLS registry
 | 
				
			||||||
type ErrHTTPProto struct {
 | 
					type httpProtoError struct {
 | 
				
			||||||
	OrigErr string
 | 
						cause error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (err ErrHTTPProto) Error() string {
 | 
					func (e httpProtoError) Error() string {
 | 
				
			||||||
	return err.OrigErr
 | 
						return e.cause.Error()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ RegistryClient = &client{}
 | 
					var _ RegistryClient = &client{}
 | 
				
			||||||
@@ -78,7 +71,7 @@ func (c *client) MountBlob(ctx context.Context, sourceRef reference.Canonical, t
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	repoEndpoint.actions = trust.ActionsPushAndPull
 | 
						repoEndpoint.actions = []string{"pull", "push"}
 | 
				
			||||||
	repo, err := c.getRepositoryForReference(ctx, targetRef, repoEndpoint)
 | 
						repo, err := c.getRepositoryForReference(ctx, targetRef, repoEndpoint)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -104,7 +97,7 @@ func (c *client) PutManifest(ctx context.Context, ref reference.Named, manifest
 | 
				
			|||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repoEndpoint.actions = trust.ActionsPushAndPull
 | 
						repoEndpoint.actions = []string{"pull", "push"}
 | 
				
			||||||
	repo, err := c.getRepositoryForReference(ctx, ref, repoEndpoint)
 | 
						repo, err := c.getRepositoryForReference(ctx, ref, repoEndpoint)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
@@ -121,7 +114,10 @@ func (c *client) PutManifest(ctx context.Context, ref reference.Named, manifest
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dgst, err := manifestService.Put(ctx, manifest, opts...)
 | 
						dgst, err := manifestService.Put(ctx, manifest, opts...)
 | 
				
			||||||
	return dgst, errors.Wrapf(err, "failed to put manifest %s", ref)
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return dgst, errors.Wrapf(err, "failed to put manifest %s", ref)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return dgst, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *client) getRepositoryForReference(ctx context.Context, ref reference.Named, repoEndpoint repositoryEndpoint) (distribution.Repository, error) {
 | 
					func (c *client) getRepositoryForReference(ctx context.Context, ref reference.Named, repoEndpoint repositoryEndpoint) (distribution.Repository, error) {
 | 
				
			||||||
@@ -135,7 +131,7 @@ func (c *client) getRepositoryForReference(ctx context.Context, ref reference.Na
 | 
				
			|||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !repoEndpoint.endpoint.TLSConfig.InsecureSkipVerify {
 | 
							if !repoEndpoint.endpoint.TLSConfig.InsecureSkipVerify {
 | 
				
			||||||
			return nil, ErrHTTPProto{OrigErr: err.Error()}
 | 
								return nil, httpProtoError{cause: err}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// --insecure was set; fall back to plain HTTP
 | 
							// --insecure was set; fall back to plain HTTP
 | 
				
			||||||
		if url := repoEndpoint.endpoint.URL; url != nil && url.Scheme == "https" {
 | 
							if url := repoEndpoint.endpoint.URL; url != nil && url.Scheme == "https" {
 | 
				
			||||||
@@ -157,7 +153,10 @@ func (c *client) getHTTPTransportForRepoEndpoint(ctx context.Context, repoEndpoi
 | 
				
			|||||||
		c.userAgent,
 | 
							c.userAgent,
 | 
				
			||||||
		repoEndpoint.actions,
 | 
							repoEndpoint.actions,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	return httpTransport, errors.Wrap(err, "failed to configure transport")
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.Wrap(err, "failed to configure transport")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return httpTransport, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetManifest returns an ImageManifest for the reference
 | 
					// GetManifest returns an ImageManifest for the reference
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								vendor/github.com/docker/cli/cli/registry/client/endpoint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/docker/cli/cli/registry/client/endpoint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -6,7 +6,6 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/distribution/reference"
 | 
						"github.com/distribution/reference"
 | 
				
			||||||
	"github.com/docker/cli/cli/trust"
 | 
					 | 
				
			||||||
	"github.com/docker/distribution/registry/client/auth"
 | 
						"github.com/docker/distribution/registry/client/auth"
 | 
				
			||||||
	"github.com/docker/distribution/registry/client/transport"
 | 
						"github.com/docker/distribution/registry/client/transport"
 | 
				
			||||||
	registrytypes "github.com/docker/docker/api/types/registry"
 | 
						registrytypes "github.com/docker/docker/api/types/registry"
 | 
				
			||||||
@@ -31,10 +30,7 @@ func (r repositoryEndpoint) BaseURL() string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newDefaultRepositoryEndpoint(ref reference.Named, insecure bool) (repositoryEndpoint, error) {
 | 
					func newDefaultRepositoryEndpoint(ref reference.Named, insecure bool) (repositoryEndpoint, error) {
 | 
				
			||||||
	repoInfo, err := registry.ParseRepositoryInfo(ref)
 | 
						repoInfo, _ := registry.ParseRepositoryInfo(ref)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return repositoryEndpoint{}, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	endpoint, err := getDefaultEndpointFromRepoInfo(repoInfo)
 | 
						endpoint, err := getDefaultEndpointFromRepoInfo(repoInfo)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return repositoryEndpoint{}, err
 | 
							return repositoryEndpoint{}, err
 | 
				
			||||||
@@ -94,7 +90,7 @@ func getHTTPTransport(authConfig registrytypes.AuthConfig, endpoint registry.API
 | 
				
			|||||||
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
 | 
							modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if len(actions) == 0 {
 | 
							if len(actions) == 0 {
 | 
				
			||||||
			actions = trust.ActionsPullOnly
 | 
								actions = []string{"pull"}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		creds := registry.NewStaticCredentialStore(&authConfig)
 | 
							creds := registry.NewStaticCredentialStore(&authConfig)
 | 
				
			||||||
		tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, actions...)
 | 
							tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, actions...)
 | 
				
			||||||
@@ -104,14 +100,11 @@ func getHTTPTransport(authConfig registrytypes.AuthConfig, endpoint registry.API
 | 
				
			|||||||
	return transport.NewTransport(base, modifiers...), nil
 | 
						return transport.NewTransport(base, modifiers...), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RepoNameForReference returns the repository name from a reference
 | 
					// RepoNameForReference returns the repository name from a reference.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Deprecated: this function is no longer used and will be removed in the next release.
 | 
				
			||||||
func RepoNameForReference(ref reference.Named) (string, error) {
 | 
					func RepoNameForReference(ref reference.Named) (string, error) {
 | 
				
			||||||
	// insecure is fine since this only returns the name
 | 
						return reference.Path(reference.TrimNamed(ref)), nil
 | 
				
			||||||
	repo, err := newDefaultRepositoryEndpoint(ref, false)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return "", err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return repo.Name(), nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type existingTokenHandler struct {
 | 
					type existingTokenHandler struct {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								vendor/github.com/docker/cli/cli/registry/client/fetcher.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/docker/cli/cli/registry/client/fetcher.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -220,10 +220,7 @@ func (c *client) iterateEndpoints(ctx context.Context, namedRef reference.Named,
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repoInfo, err := registry.ParseRepositoryInfo(namedRef)
 | 
						repoInfo, _ := registry.ParseRepositoryInfo(namedRef)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	confirmedTLSRegistries := make(map[string]bool)
 | 
						confirmedTLSRegistries := make(map[string]bool)
 | 
				
			||||||
	for _, endpoint := range endpoints {
 | 
						for _, endpoint := range endpoints {
 | 
				
			||||||
@@ -241,7 +238,8 @@ func (c *client) iterateEndpoints(ctx context.Context, namedRef reference.Named,
 | 
				
			|||||||
		repo, err := c.getRepositoryForReference(ctx, namedRef, repoEndpoint)
 | 
							repo, err := c.getRepositoryForReference(ctx, namedRef, repoEndpoint)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			logrus.Debugf("error %s with repo endpoint %+v", err, repoEndpoint)
 | 
								logrus.Debugf("error %s with repo endpoint %+v", err, repoEndpoint)
 | 
				
			||||||
			if _, ok := err.(ErrHTTPProto); ok {
 | 
								var protoErr httpProtoError
 | 
				
			||||||
 | 
								if errors.As(err, &protoErr) {
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
@@ -272,11 +270,6 @@ func (c *client) iterateEndpoints(ctx context.Context, namedRef reference.Named,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// allEndpoints returns a list of endpoints ordered by priority (v2, http).
 | 
					// allEndpoints returns a list of endpoints ordered by priority (v2, http).
 | 
				
			||||||
func allEndpoints(namedRef reference.Named, insecure bool) ([]registry.APIEndpoint, error) {
 | 
					func allEndpoints(namedRef reference.Named, insecure bool) ([]registry.APIEndpoint, error) {
 | 
				
			||||||
	repoInfo, err := registry.ParseRepositoryInfo(namedRef)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var serviceOpts registry.ServiceOptions
 | 
						var serviceOpts registry.ServiceOptions
 | 
				
			||||||
	if insecure {
 | 
						if insecure {
 | 
				
			||||||
		logrus.Debugf("allowing insecure registry for: %s", reference.Domain(namedRef))
 | 
							logrus.Debugf("allowing insecure registry for: %s", reference.Domain(namedRef))
 | 
				
			||||||
@@ -286,6 +279,7 @@ func allEndpoints(namedRef reference.Named, insecure bool) ([]registry.APIEndpoi
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return []registry.APIEndpoint{}, err
 | 
							return []registry.APIEndpoint{}, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						repoInfo, _ := registry.ParseRepositoryInfo(namedRef)
 | 
				
			||||||
	endpoints, err := registryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
 | 
						endpoints, err := registryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
 | 
				
			||||||
	logrus.Debugf("endpoints for %s: %v", namedRef, endpoints)
 | 
						logrus.Debugf("endpoints for %s: %v", namedRef, endpoints)
 | 
				
			||||||
	return endpoints, err
 | 
						return endpoints, err
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								vendor/github.com/docker/cli/cli/trust/trust.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/docker/cli/cli/trust/trust.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -40,10 +40,11 @@ var (
 | 
				
			|||||||
	ActionsPullOnly = []string{"pull"}
 | 
						ActionsPullOnly = []string{"pull"}
 | 
				
			||||||
	// ActionsPushAndPull defines the actions for read-write interactions with a Notary Repository
 | 
						// ActionsPushAndPull defines the actions for read-write interactions with a Notary Repository
 | 
				
			||||||
	ActionsPushAndPull = []string{"pull", "push"}
 | 
						ActionsPushAndPull = []string{"pull", "push"}
 | 
				
			||||||
	// NotaryServer is the endpoint serving the Notary trust server
 | 
					 | 
				
			||||||
	NotaryServer = "https://notary.docker.io"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NotaryServer is the endpoint serving the Notary trust server
 | 
				
			||||||
 | 
					const NotaryServer = "https://notary.docker.io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetTrustDirectory returns the base trust directory name
 | 
					// GetTrustDirectory returns the base trust directory name
 | 
				
			||||||
func GetTrustDirectory() string {
 | 
					func GetTrustDirectory() string {
 | 
				
			||||||
	return filepath.Join(config.Dir(), "trust")
 | 
						return filepath.Join(config.Dir(), "trust")
 | 
				
			||||||
@@ -238,6 +239,20 @@ func NotaryError(repoName string, err error) error {
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddToAllSignableRoles attempts to add the image target to all the top level
 | 
				
			||||||
 | 
					// delegation roles we can (based on whether we have the signing key and whether
 | 
				
			||||||
 | 
					// the role's path allows us to).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If there are no delegation roles, we add to the targets role.
 | 
				
			||||||
 | 
					func AddToAllSignableRoles(repo client.Repository, target *client.Target) error {
 | 
				
			||||||
 | 
						signableRoles, err := GetSignableRoles(repo, target)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return repo.AddTarget(target, signableRoles...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetSignableRoles returns a list of roles for which we have valid signing
 | 
					// GetSignableRoles returns a list of roles for which we have valid signing
 | 
				
			||||||
// keys, given a notary repository and a target
 | 
					// keys, given a notary repository and a target
 | 
				
			||||||
func GetSignableRoles(repo client.Repository, target *client.Target) ([]data.RoleName, error) {
 | 
					func GetSignableRoles(repo client.Repository, target *client.Target) ([]data.RoleName, error) {
 | 
				
			||||||
@@ -307,11 +322,7 @@ func GetImageReferencesAndAuth(ctx context.Context,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Resolve the Repository name from fqn to RepositoryInfo
 | 
						// Resolve the Repository name from fqn to RepositoryInfo
 | 
				
			||||||
	repoInfo, err := registry.ParseRepositoryInfo(ref)
 | 
						repoInfo, _ := registry.ParseRepositoryInfo(ref)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return ImageRefAndAuth{}, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	authConfig := authResolver(ctx, repoInfo.Index)
 | 
						authConfig := authResolver(ctx, repoInfo.Index)
 | 
				
			||||||
	return ImageRefAndAuth{
 | 
						return ImageRefAndAuth{
 | 
				
			||||||
		original:   imgName,
 | 
							original:   imgName,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										143
									
								
								vendor/github.com/docker/cli/cli/trust/trust_push.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/github.com/docker/cli/cli/trust/trust_push.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					package trust
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/distribution/reference"
 | 
				
			||||||
 | 
						"github.com/docker/cli/cli/internal/jsonstream"
 | 
				
			||||||
 | 
						"github.com/docker/cli/cli/streams"
 | 
				
			||||||
 | 
						"github.com/docker/docker/api/types"
 | 
				
			||||||
 | 
						registrytypes "github.com/docker/docker/api/types/registry"
 | 
				
			||||||
 | 
						"github.com/docker/docker/registry"
 | 
				
			||||||
 | 
						"github.com/opencontainers/go-digest"
 | 
				
			||||||
 | 
						"github.com/pkg/errors"
 | 
				
			||||||
 | 
						"github.com/theupdateframework/notary/client"
 | 
				
			||||||
 | 
						"github.com/theupdateframework/notary/tuf/data"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Streams is an interface which exposes the standard input and output streams.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Same interface as [github.com/docker/cli/cli/command.Streams] but defined here to prevent a circular import.
 | 
				
			||||||
 | 
					type Streams interface {
 | 
				
			||||||
 | 
						In() *streams.In
 | 
				
			||||||
 | 
						Out() *streams.Out
 | 
				
			||||||
 | 
						Err() *streams.Out
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PushTrustedReference pushes a canonical reference to the trust server.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//nolint:gocyclo
 | 
				
			||||||
 | 
					func PushTrustedReference(ctx context.Context, ioStreams Streams, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig registrytypes.AuthConfig, in io.Reader, userAgent string) error {
 | 
				
			||||||
 | 
						// If it is a trusted push we would like to find the target entry which match the
 | 
				
			||||||
 | 
						// tag provided in the function and then do an AddTarget later.
 | 
				
			||||||
 | 
						notaryTarget := &client.Target{}
 | 
				
			||||||
 | 
						// Count the times of calling for handleTarget,
 | 
				
			||||||
 | 
						// if it is called more that once, that should be considered an error in a trusted push.
 | 
				
			||||||
 | 
						cnt := 0
 | 
				
			||||||
 | 
						handleTarget := func(msg jsonstream.JSONMessage) {
 | 
				
			||||||
 | 
							cnt++
 | 
				
			||||||
 | 
							if cnt > 1 {
 | 
				
			||||||
 | 
								// handleTarget should only be called once. This will be treated as an error.
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var pushResult types.PushResult
 | 
				
			||||||
 | 
							err := json.Unmarshal(*msg.Aux, &pushResult)
 | 
				
			||||||
 | 
							if err == nil && pushResult.Tag != "" {
 | 
				
			||||||
 | 
								if dgst, err := digest.Parse(pushResult.Digest); err == nil {
 | 
				
			||||||
 | 
									h, err := hex.DecodeString(dgst.Hex())
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										notaryTarget = nil
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									notaryTarget.Name = pushResult.Tag
 | 
				
			||||||
 | 
									notaryTarget.Hashes = data.Hashes{string(dgst.Algorithm()): h}
 | 
				
			||||||
 | 
									notaryTarget.Length = int64(pushResult.Size)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tag string
 | 
				
			||||||
 | 
						switch x := ref.(type) {
 | 
				
			||||||
 | 
						case reference.Canonical:
 | 
				
			||||||
 | 
							return errors.New("cannot push a digest reference")
 | 
				
			||||||
 | 
						case reference.NamedTagged:
 | 
				
			||||||
 | 
							tag = x.Tag()
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							// We want trust signatures to always take an explicit tag,
 | 
				
			||||||
 | 
							// otherwise it will act as an untrusted push.
 | 
				
			||||||
 | 
							if err := jsonstream.Display(ctx, in, ioStreams.Out()); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_, _ = fmt.Fprintln(ioStreams.Err(), "No tag specified, skipping trust metadata push")
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := jsonstream.Display(ctx, in, ioStreams.Out(), jsonstream.WithAuxCallback(handleTarget)); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if cnt > 1 {
 | 
				
			||||||
 | 
							return errors.Errorf("internal error: only one call to handleTarget expected")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if notaryTarget == nil {
 | 
				
			||||||
 | 
							return errors.Errorf("no targets found, provide a specific tag in order to sign it")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, _ = fmt.Fprintln(ioStreams.Out(), "Signing and pushing trust metadata")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repo, err := GetNotaryRepository(ioStreams.In(), ioStreams.Out(), userAgent, repoInfo, &authConfig, "push", "pull")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return errors.Wrap(err, "error establishing connection to trust repository")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// get the latest repository metadata so we can figure out which roles to sign
 | 
				
			||||||
 | 
						_, err = repo.ListTargets()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch err.(type) {
 | 
				
			||||||
 | 
						case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
 | 
				
			||||||
 | 
							keys := repo.GetCryptoService().ListKeys(data.CanonicalRootRole)
 | 
				
			||||||
 | 
							var rootKeyID string
 | 
				
			||||||
 | 
							// always select the first root key
 | 
				
			||||||
 | 
							if len(keys) > 0 {
 | 
				
			||||||
 | 
								sort.Strings(keys)
 | 
				
			||||||
 | 
								rootKeyID = keys[0]
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								rootPublicKey, err := repo.GetCryptoService().Create(data.CanonicalRootRole, "", data.ECDSAKey)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								rootKeyID = rootPublicKey.ID()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Initialize the notary repository with a remotely managed snapshot key
 | 
				
			||||||
 | 
							if err := repo.Initialize([]string{rootKeyID}, data.CanonicalSnapshotRole); err != nil {
 | 
				
			||||||
 | 
								return NotaryError(repoInfo.Name.Name(), err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_, _ = fmt.Fprintf(ioStreams.Out(), "Finished initializing %q\n", repoInfo.Name.Name())
 | 
				
			||||||
 | 
							err = repo.AddTarget(notaryTarget, data.CanonicalTargetsRole)
 | 
				
			||||||
 | 
						case nil:
 | 
				
			||||||
 | 
							// already initialized and we have successfully downloaded the latest metadata
 | 
				
			||||||
 | 
							err = AddToAllSignableRoles(repo, notaryTarget)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return NotaryError(repoInfo.Name.Name(), err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							err = repo.Publish()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							err = errors.Wrapf(err, "failed to sign %s:%s", repoInfo.Name.Name(), tag)
 | 
				
			||||||
 | 
							return NotaryError(repoInfo.Name.Name(), err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, _ = fmt.Fprintf(ioStreams.Out(), "Successfully signed %s:%s\n", repoInfo.Name.Name(), tag)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								vendor/github.com/docker/cli/cli/trust/trust_tag.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/docker/cli/cli/trust/trust_tag.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					package trust
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/distribution/reference"
 | 
				
			||||||
 | 
						"github.com/docker/docker/client"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TagTrusted tags a trusted ref. It is a shallow wrapper around [client.Client.ImageTag]
 | 
				
			||||||
 | 
					// that updates the given image references to their familiar format for tagging
 | 
				
			||||||
 | 
					// and printing.
 | 
				
			||||||
 | 
					func TagTrusted(ctx context.Context, apiClient client.ImageAPIClient, out io.Writer, trustedRef reference.Canonical, ref reference.NamedTagged) error {
 | 
				
			||||||
 | 
						// Use familiar references when interacting with client and output
 | 
				
			||||||
 | 
						familiarRef := reference.FamiliarString(ref)
 | 
				
			||||||
 | 
						trustedFamiliarRef := reference.FamiliarString(trustedRef)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, _ = fmt.Fprintf(out, "Tagging %s as %s\n", trustedFamiliarRef, familiarRef)
 | 
				
			||||||
 | 
						return apiClient.ImageTag(ctx, trustedFamiliarRef, familiarRef)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								vendor/github.com/docker/cli/opts/duration.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/docker/cli/opts/duration.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,9 +1,8 @@
 | 
				
			|||||||
package opts
 | 
					package opts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PositiveDurationOpt is an option type for time.Duration that uses a pointer.
 | 
					// PositiveDurationOpt is an option type for time.Duration that uses a pointer.
 | 
				
			||||||
@@ -20,7 +19,7 @@ func (d *PositiveDurationOpt) Set(s string) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if *d.DurationOpt.value < 0 {
 | 
						if *d.DurationOpt.value < 0 {
 | 
				
			||||||
		return errors.Errorf("duration cannot be negative")
 | 
							return errors.New("duration cannot be negative")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								vendor/github.com/docker/cli/opts/env.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/docker/cli/opts/env.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,10 +1,9 @@
 | 
				
			|||||||
package opts
 | 
					package opts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ValidateEnv validates an environment variable and returns it.
 | 
					// ValidateEnv validates an environment variable and returns it.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								vendor/github.com/docker/cli/opts/gpus.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/docker/cli/opts/gpus.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,12 +2,12 @@ package opts
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/csv"
 | 
						"encoding/csv"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/docker/api/types/container"
 | 
						"github.com/docker/docker/api/types/container"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GpuOpts is a Value type for parsing mounts
 | 
					// GpuOpts is a Value type for parsing mounts
 | 
				
			||||||
@@ -20,7 +20,14 @@ func parseCount(s string) (int, error) {
 | 
				
			|||||||
		return -1, nil
 | 
							return -1, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	i, err := strconv.Atoi(s)
 | 
						i, err := strconv.Atoi(s)
 | 
				
			||||||
	return i, errors.Wrap(err, "count must be an integer")
 | 
						if err != nil {
 | 
				
			||||||
 | 
							var numErr *strconv.NumError
 | 
				
			||||||
 | 
							if errors.As(err, &numErr) {
 | 
				
			||||||
 | 
								err = numErr.Err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 0, fmt.Errorf(`invalid count (%s): value must be either "all" or an integer: %w`, s, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return i, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Set a new mount value
 | 
					// Set a new mount value
 | 
				
			||||||
@@ -69,7 +76,7 @@ func (o *GpuOpts) Set(value string) error {
 | 
				
			|||||||
			r := csv.NewReader(strings.NewReader(val))
 | 
								r := csv.NewReader(strings.NewReader(val))
 | 
				
			||||||
			optFields, err := r.Read()
 | 
								optFields, err := r.Read()
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "failed to read gpu options")
 | 
									return fmt.Errorf("failed to read gpu options: %w", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			req.Options = ConvertKVStringsToMap(optFields)
 | 
								req.Options = ConvertKVStringsToMap(optFields)
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								vendor/github.com/docker/cli/opts/mount.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/docker/cli/opts/mount.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -135,8 +135,7 @@ func (m *MountOpt) Set(value string) error {
 | 
				
			|||||||
				// TODO: implicitly set propagation and error if the user specifies a propagation in a future refactor/UX polish pass
 | 
									// TODO: implicitly set propagation and error if the user specifies a propagation in a future refactor/UX polish pass
 | 
				
			||||||
				// https://github.com/docker/cli/pull/4316#discussion_r1341974730
 | 
									// https://github.com/docker/cli/pull/4316#discussion_r1341974730
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return fmt.Errorf("invalid value for %s: %s (must be \"enabled\", \"disabled\", \"writable\", or \"readonly\")",
 | 
									return fmt.Errorf(`invalid value for %s: %s (must be "enabled", "disabled", "writable", or "readonly")`, key, val)
 | 
				
			||||||
					key, val)
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case "volume-subpath":
 | 
							case "volume-subpath":
 | 
				
			||||||
			volumeOptions().Subpath = val
 | 
								volumeOptions().Subpath = val
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								vendor/github.com/docker/cli/opts/network.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/docker/cli/opts/network.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -89,7 +89,11 @@ func (n *NetworkOpt) Set(value string) error { //nolint:gocyclo
 | 
				
			|||||||
			case gwPriorityOpt:
 | 
								case gwPriorityOpt:
 | 
				
			||||||
				netOpt.GwPriority, err = strconv.Atoi(val)
 | 
									netOpt.GwPriority, err = strconv.Atoi(val)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return fmt.Errorf("invalid gw-priority: %w", err)
 | 
										var numErr *strconv.NumError
 | 
				
			||||||
 | 
										if errors.As(err, &numErr) {
 | 
				
			||||||
 | 
											err = numErr.Err
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return fmt.Errorf("invalid gw-priority (%s): %w", val, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return errors.New("invalid field key " + key)
 | 
									return errors.New("invalid field key " + key)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								vendor/github.com/docker/cli/opts/opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/docker/cli/opts/opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,7 @@
 | 
				
			|||||||
package opts
 | 
					package opts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"math/big"
 | 
						"math/big"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
@@ -9,8 +10,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/docker/docker/api/types/filters"
 | 
						"github.com/docker/docker/api/types/filters"
 | 
				
			||||||
	units "github.com/docker/go-units"
 | 
						"github.com/docker/go-units"
 | 
				
			||||||
	"github.com/pkg/errors"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								vendor/github.com/docker/cli/opts/opts_deprecated.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/docker/cli/opts/opts_deprecated.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					package opts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "github.com/docker/cli/opts/swarmopts"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PortOpt represents a port config in swarm mode.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Deprecated: use [swarmopts.PortOpt]
 | 
				
			||||||
 | 
					type PortOpt = swarmopts.PortOpt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ConfigOpt is a Value type for parsing configs.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Deprecated: use [swarmopts.ConfigOpt]
 | 
				
			||||||
 | 
					type ConfigOpt = swarmopts.ConfigOpt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SecretOpt is a Value type for parsing secrets
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Deprecated: use [swarmopts.SecretOpt]
 | 
				
			||||||
 | 
					type SecretOpt = swarmopts.SecretOpt
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package opts
 | 
					package swarmopts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/csv"
 | 
						"encoding/csv"
 | 
				
			||||||
@@ -8,12 +8,12 @@ import (
 | 
				
			|||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	swarmtypes "github.com/docker/docker/api/types/swarm"
 | 
						"github.com/docker/docker/api/types/swarm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ConfigOpt is a Value type for parsing configs
 | 
					// ConfigOpt is a Value type for parsing configs
 | 
				
			||||||
type ConfigOpt struct {
 | 
					type ConfigOpt struct {
 | 
				
			||||||
	values []*swarmtypes.ConfigReference
 | 
						values []*swarm.ConfigReference
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Set a new config value
 | 
					// Set a new config value
 | 
				
			||||||
@@ -24,8 +24,8 @@ func (o *ConfigOpt) Set(value string) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	options := &swarmtypes.ConfigReference{
 | 
						options := &swarm.ConfigReference{
 | 
				
			||||||
		File: &swarmtypes.ConfigReferenceFileTarget{
 | 
							File: &swarm.ConfigReferenceFileTarget{
 | 
				
			||||||
			UID:  "0",
 | 
								UID:  "0",
 | 
				
			||||||
			GID:  "0",
 | 
								GID:  "0",
 | 
				
			||||||
			Mode: 0o444,
 | 
								Mode: 0o444,
 | 
				
			||||||
@@ -95,6 +95,6 @@ func (o *ConfigOpt) String() string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Value returns the config requests
 | 
					// Value returns the config requests
 | 
				
			||||||
func (o *ConfigOpt) Value() []*swarmtypes.ConfigReference {
 | 
					func (o *ConfigOpt) Value() []*swarm.ConfigReference {
 | 
				
			||||||
	return o.values
 | 
						return o.values
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package opts
 | 
					package swarmopts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/csv"
 | 
						"encoding/csv"
 | 
				
			||||||
@@ -46,42 +46,50 @@ func (p *PortOpt) Set(value string) error {
 | 
				
			|||||||
			// TODO(thaJeztah): these options should not be case-insensitive.
 | 
								// TODO(thaJeztah): these options should not be case-insensitive.
 | 
				
			||||||
			key, val, ok := strings.Cut(strings.ToLower(field), "=")
 | 
								key, val, ok := strings.Cut(strings.ToLower(field), "=")
 | 
				
			||||||
			if !ok || key == "" {
 | 
								if !ok || key == "" {
 | 
				
			||||||
				return fmt.Errorf("invalid field %s", field)
 | 
									return fmt.Errorf("invalid field: %s", field)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			switch key {
 | 
								switch key {
 | 
				
			||||||
			case portOptProtocol:
 | 
								case portOptProtocol:
 | 
				
			||||||
				if val != string(swarm.PortConfigProtocolTCP) && val != string(swarm.PortConfigProtocolUDP) && val != string(swarm.PortConfigProtocolSCTP) {
 | 
									if val != string(swarm.PortConfigProtocolTCP) && val != string(swarm.PortConfigProtocolUDP) && val != string(swarm.PortConfigProtocolSCTP) {
 | 
				
			||||||
					return fmt.Errorf("invalid protocol value %s", val)
 | 
										return fmt.Errorf("invalid protocol value '%s'", val)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				pConfig.Protocol = swarm.PortConfigProtocol(val)
 | 
									pConfig.Protocol = swarm.PortConfigProtocol(val)
 | 
				
			||||||
			case portOptMode:
 | 
								case portOptMode:
 | 
				
			||||||
				if val != string(swarm.PortConfigPublishModeIngress) && val != string(swarm.PortConfigPublishModeHost) {
 | 
									if val != string(swarm.PortConfigPublishModeIngress) && val != string(swarm.PortConfigPublishModeHost) {
 | 
				
			||||||
					return fmt.Errorf("invalid publish mode value %s", val)
 | 
										return fmt.Errorf("invalid publish mode value (%s): must be either '%s' or '%s'", val, swarm.PortConfigPublishModeIngress, swarm.PortConfigPublishModeHost)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				pConfig.PublishMode = swarm.PortConfigPublishMode(val)
 | 
									pConfig.PublishMode = swarm.PortConfigPublishMode(val)
 | 
				
			||||||
			case portOptTargetPort:
 | 
								case portOptTargetPort:
 | 
				
			||||||
				tPort, err := strconv.ParseUint(val, 10, 16)
 | 
									tPort, err := strconv.ParseUint(val, 10, 16)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return err
 | 
										var numErr *strconv.NumError
 | 
				
			||||||
 | 
										if errors.As(err, &numErr) {
 | 
				
			||||||
 | 
											err = numErr.Err
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return fmt.Errorf("invalid target port (%s): value must be an integer: %w", val, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				pConfig.TargetPort = uint32(tPort)
 | 
									pConfig.TargetPort = uint32(tPort)
 | 
				
			||||||
			case portOptPublishedPort:
 | 
								case portOptPublishedPort:
 | 
				
			||||||
				pPort, err := strconv.ParseUint(val, 10, 16)
 | 
									pPort, err := strconv.ParseUint(val, 10, 16)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return err
 | 
										var numErr *strconv.NumError
 | 
				
			||||||
 | 
										if errors.As(err, &numErr) {
 | 
				
			||||||
 | 
											err = numErr.Err
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return fmt.Errorf("invalid published port (%s): value must be an integer: %w", val, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				pConfig.PublishedPort = uint32(pPort)
 | 
									pConfig.PublishedPort = uint32(pPort)
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return fmt.Errorf("invalid field key %s", key)
 | 
									return fmt.Errorf("invalid field key: %s", key)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if pConfig.TargetPort == 0 {
 | 
							if pConfig.TargetPort == 0 {
 | 
				
			||||||
			return fmt.Errorf("missing mandatory field %q", portOptTargetPort)
 | 
								return fmt.Errorf("missing mandatory field '%s'", portOptTargetPort)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if pConfig.PublishMode == "" {
 | 
							if pConfig.PublishMode == "" {
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package opts
 | 
					package swarmopts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/csv"
 | 
						"encoding/csv"
 | 
				
			||||||
@@ -8,12 +8,12 @@ import (
 | 
				
			|||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	swarmtypes "github.com/docker/docker/api/types/swarm"
 | 
						"github.com/docker/docker/api/types/swarm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SecretOpt is a Value type for parsing secrets
 | 
					// SecretOpt is a Value type for parsing secrets
 | 
				
			||||||
type SecretOpt struct {
 | 
					type SecretOpt struct {
 | 
				
			||||||
	values []*swarmtypes.SecretReference
 | 
						values []*swarm.SecretReference
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Set a new secret value
 | 
					// Set a new secret value
 | 
				
			||||||
@@ -24,8 +24,8 @@ func (o *SecretOpt) Set(value string) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	options := &swarmtypes.SecretReference{
 | 
						options := &swarm.SecretReference{
 | 
				
			||||||
		File: &swarmtypes.SecretReferenceFileTarget{
 | 
							File: &swarm.SecretReferenceFileTarget{
 | 
				
			||||||
			UID:  "0",
 | 
								UID:  "0",
 | 
				
			||||||
			GID:  "0",
 | 
								GID:  "0",
 | 
				
			||||||
			Mode: 0o444,
 | 
								Mode: 0o444,
 | 
				
			||||||
@@ -94,6 +94,6 @@ func (o *SecretOpt) String() string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Value returns the secret requests
 | 
					// Value returns the secret requests
 | 
				
			||||||
func (o *SecretOpt) Value() []*swarmtypes.SecretReference {
 | 
					func (o *SecretOpt) Value() []*swarm.SecretReference {
 | 
				
			||||||
	return o.values
 | 
						return o.values
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								vendor/github.com/docker/docker/api/swagger.yaml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/docker/docker/api/swagger.yaml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -5508,8 +5508,11 @@ definitions:
 | 
				
			|||||||
          com.example.some-other-label: "some-other-value"
 | 
					          com.example.some-other-label: "some-other-value"
 | 
				
			||||||
      Data:
 | 
					      Data:
 | 
				
			||||||
        description: |
 | 
					        description: |
 | 
				
			||||||
          Base64-url-safe-encoded ([RFC 4648](https://tools.ietf.org/html/rfc4648#section-5))
 | 
					          Data is the data to store as a secret, formatted as a Base64-url-safe-encoded
 | 
				
			||||||
          data to store as secret.
 | 
					          ([RFC 4648](https://tools.ietf.org/html/rfc4648#section-5)) string.
 | 
				
			||||||
 | 
					          It must be empty if the Driver field is set, in which case the data is
 | 
				
			||||||
 | 
					          loaded from an external secret store. The maximum allowed size is 500KB,
 | 
				
			||||||
 | 
					          as defined in [MaxSecretSize](https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/api/validation#MaxSecretSize).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          This field is only used to _create_ a secret, and is not returned by
 | 
					          This field is only used to _create_ a secret, and is not returned by
 | 
				
			||||||
          other endpoints.
 | 
					          other endpoints.
 | 
				
			||||||
@@ -5560,8 +5563,9 @@ definitions:
 | 
				
			|||||||
          type: "string"
 | 
					          type: "string"
 | 
				
			||||||
      Data:
 | 
					      Data:
 | 
				
			||||||
        description: |
 | 
					        description: |
 | 
				
			||||||
          Base64-url-safe-encoded ([RFC 4648](https://tools.ietf.org/html/rfc4648#section-5))
 | 
					          Data is the data to store as a config, formatted as a Base64-url-safe-encoded
 | 
				
			||||||
          config data.
 | 
					          ([RFC 4648](https://tools.ietf.org/html/rfc4648#section-5)) string.
 | 
				
			||||||
 | 
					          The maximum allowed size is 1000KB, as defined in [MaxConfigSize](https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/manager/controlapi#MaxConfigSize).
 | 
				
			||||||
        type: "string"
 | 
					        type: "string"
 | 
				
			||||||
      Templating:
 | 
					      Templating:
 | 
				
			||||||
        description: |
 | 
					        description: |
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								vendor/github.com/docker/docker/api/types/registry/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/docker/docker/api/types/registry/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -49,15 +49,17 @@ func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UnmarshalJSON sets the IPNet from a byte array of JSON
 | 
					// UnmarshalJSON sets the IPNet from a byte array of JSON
 | 
				
			||||||
func (ipnet *NetIPNet) UnmarshalJSON(b []byte) (err error) {
 | 
					func (ipnet *NetIPNet) UnmarshalJSON(b []byte) error {
 | 
				
			||||||
	var ipnetStr string
 | 
						var ipnetStr string
 | 
				
			||||||
	if err = json.Unmarshal(b, &ipnetStr); err == nil {
 | 
						if err := json.Unmarshal(b, &ipnetStr); err != nil {
 | 
				
			||||||
		var cidr *net.IPNet
 | 
							return err
 | 
				
			||||||
		if _, cidr, err = net.ParseCIDR(ipnetStr); err == nil {
 | 
					 | 
				
			||||||
			*ipnet = NetIPNet(*cidr)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						_, cidr, err := net.ParseCIDR(ipnetStr)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						*ipnet = NetIPNet(*cidr)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IndexInfo contains information about a registry
 | 
					// IndexInfo contains information about a registry
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								vendor/github.com/docker/docker/api/types/swarm/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/docker/docker/api/types/swarm/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -12,6 +12,12 @@ type Config struct {
 | 
				
			|||||||
// ConfigSpec represents a config specification from a config in swarm
 | 
					// ConfigSpec represents a config specification from a config in swarm
 | 
				
			||||||
type ConfigSpec struct {
 | 
					type ConfigSpec struct {
 | 
				
			||||||
	Annotations
 | 
						Annotations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Data is the data to store as a config.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// The maximum allowed size is 1000KB, as defined in [MaxConfigSize].
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// [MaxConfigSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/manager/controlapi#MaxConfigSize
 | 
				
			||||||
	Data []byte `json:",omitempty"`
 | 
						Data []byte `json:",omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Templating controls whether and how to evaluate the config payload as
 | 
						// Templating controls whether and how to evaluate the config payload as
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								vendor/github.com/docker/docker/api/types/swarm/secret.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/docker/docker/api/types/swarm/secret.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -12,8 +12,22 @@ type Secret struct {
 | 
				
			|||||||
// SecretSpec represents a secret specification from a secret in swarm
 | 
					// SecretSpec represents a secret specification from a secret in swarm
 | 
				
			||||||
type SecretSpec struct {
 | 
					type SecretSpec struct {
 | 
				
			||||||
	Annotations
 | 
						Annotations
 | 
				
			||||||
	Data   []byte  `json:",omitempty"`
 | 
					
 | 
				
			||||||
	Driver *Driver `json:",omitempty"` // name of the secrets driver used to fetch the secret's value from an external secret store
 | 
						// Data is the data to store as a secret. It must be empty if a
 | 
				
			||||||
 | 
						// [Driver] is used, in which case the data is loaded from an external
 | 
				
			||||||
 | 
						// secret store. The maximum allowed size is 500KB, as defined in
 | 
				
			||||||
 | 
						// [MaxSecretSize].
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// This field is only used to create the secret, and is not returned
 | 
				
			||||||
 | 
						// by other endpoints.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// [MaxSecretSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/api/validation#MaxSecretSize
 | 
				
			||||||
 | 
						Data []byte `json:",omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Driver is the name of the secrets driver used to fetch the secret's
 | 
				
			||||||
 | 
						// value from an external secret store. If not set, the default built-in
 | 
				
			||||||
 | 
						// store is used.
 | 
				
			||||||
 | 
						Driver *Driver `json:",omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Templating controls whether and how to evaluate the secret payload as
 | 
						// Templating controls whether and how to evaluate the secret payload as
 | 
				
			||||||
	// a template. If it is not set, no templating is used.
 | 
						// a template. If it is not set, no templating is used.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								vendor/github.com/docker/docker/client/container_create.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/docker/docker/client/container_create.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -3,6 +3,7 @@ package client // import "github.com/docker/docker/client"
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
@@ -54,6 +55,19 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
 | 
				
			|||||||
			// When using API under 1.42, the Linux daemon doesn't respect the ConsoleSize
 | 
								// When using API under 1.42, the Linux daemon doesn't respect the ConsoleSize
 | 
				
			||||||
			hostConfig.ConsoleSize = [2]uint{0, 0}
 | 
								hostConfig.ConsoleSize = [2]uint{0, 0}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if versions.LessThan(cli.ClientVersion(), "1.44") {
 | 
				
			||||||
 | 
								for _, m := range hostConfig.Mounts {
 | 
				
			||||||
 | 
									if m.BindOptions != nil {
 | 
				
			||||||
 | 
										// ReadOnlyNonRecursive can be safely ignored when API < 1.44
 | 
				
			||||||
 | 
										if m.BindOptions.ReadOnlyForceRecursive {
 | 
				
			||||||
 | 
											return response, errors.New("bind-recursive=readonly requires API v1.44 or later")
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if m.BindOptions.NonRecursive && versions.LessThan(cli.ClientVersion(), "1.40") {
 | 
				
			||||||
 | 
											return response, errors.New("bind-recursive=disabled requires API v1.40 or later")
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		hostConfig.CapAdd = normalizeCapabilities(hostConfig.CapAdd)
 | 
							hostConfig.CapAdd = normalizeCapabilities(hostConfig.CapAdd)
 | 
				
			||||||
		hostConfig.CapDrop = normalizeCapabilities(hostConfig.CapDrop)
 | 
							hostConfig.CapDrop = normalizeCapabilities(hostConfig.CapDrop)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								vendor/github.com/docker/docker/client/service_create.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/docker/docker/client/service_create.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -37,6 +37,11 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
 | 
				
			|||||||
	if err := validateServiceSpec(service); err != nil {
 | 
						if err := validateServiceSpec(service); err != nil {
 | 
				
			||||||
		return response, err
 | 
							return response, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if versions.LessThan(cli.version, "1.30") {
 | 
				
			||||||
 | 
							if err := validateAPIVersion(service, cli.version); err != nil {
 | 
				
			||||||
 | 
								return response, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ensure that the image is tagged
 | 
						// ensure that the image is tagged
 | 
				
			||||||
	var resolveWarning string
 | 
						var resolveWarning string
 | 
				
			||||||
@@ -191,3 +196,18 @@ func validateServiceSpec(s swarm.ServiceSpec) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func validateAPIVersion(c swarm.ServiceSpec, apiVersion string) error {
 | 
				
			||||||
 | 
						for _, m := range c.TaskTemplate.ContainerSpec.Mounts {
 | 
				
			||||||
 | 
							if m.BindOptions != nil {
 | 
				
			||||||
 | 
								if m.BindOptions.NonRecursive && versions.LessThan(apiVersion, "1.40") {
 | 
				
			||||||
 | 
									return errors.Errorf("bind-recursive=disabled requires API v1.40 or later")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// ReadOnlyNonRecursive can be safely ignored when API < 1.44
 | 
				
			||||||
 | 
								if m.BindOptions.ReadOnlyForceRecursive && versions.LessThan(apiVersion, "1.44") {
 | 
				
			||||||
 | 
									return errors.Errorf("bind-recursive=readonly requires API v1.44 or later")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								vendor/github.com/docker/docker/pkg/archive/archive.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/docker/docker/pkg/archive/archive.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -236,11 +236,9 @@ func (r *readCloserWrapper) Close() error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var bufioReader32KPool = &sync.Pool{
 | 
				
			||||||
	bufioReader32KPool = &sync.Pool{
 | 
						New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) },
 | 
				
			||||||
		New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) },
 | 
					}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type bufferedReader struct {
 | 
					type bufferedReader struct {
 | 
				
			||||||
	buf *bufio.Reader
 | 
						buf *bufio.Reader
 | 
				
			||||||
@@ -252,17 +250,17 @@ func newBufferedReader(r io.Reader) *bufferedReader {
 | 
				
			|||||||
	return &bufferedReader{buf}
 | 
						return &bufferedReader{buf}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *bufferedReader) Read(p []byte) (n int, err error) {
 | 
					func (r *bufferedReader) Read(p []byte) (int, error) {
 | 
				
			||||||
	if r.buf == nil {
 | 
						if r.buf == nil {
 | 
				
			||||||
		return 0, io.EOF
 | 
							return 0, io.EOF
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	n, err = r.buf.Read(p)
 | 
						n, err := r.buf.Read(p)
 | 
				
			||||||
	if err == io.EOF {
 | 
						if err == io.EOF {
 | 
				
			||||||
		r.buf.Reset(nil)
 | 
							r.buf.Reset(nil)
 | 
				
			||||||
		bufioReader32KPool.Put(r.buf)
 | 
							bufioReader32KPool.Put(r.buf)
 | 
				
			||||||
		r.buf = nil
 | 
							r.buf = nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return n, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *bufferedReader) Peek(n int) ([]byte, error) {
 | 
					func (r *bufferedReader) Peek(n int) ([]byte, error) {
 | 
				
			||||||
@@ -428,7 +426,7 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
 | 
				
			|||||||
					pipeWriter.CloseWithError(err)
 | 
										pipeWriter.CloseWithError(err)
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if _, err := copyWithBuffer(tarWriter, tarReader); err != nil {
 | 
									if err := copyWithBuffer(tarWriter, tarReader); err != nil {
 | 
				
			||||||
					pipeWriter.CloseWithError(err)
 | 
										pipeWriter.CloseWithError(err)
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -731,7 +729,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
 | 
				
			|||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_, err = copyWithBuffer(ta.TarWriter, file)
 | 
							err = copyWithBuffer(ta.TarWriter, file)
 | 
				
			||||||
		file.Close()
 | 
							file.Close()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
@@ -778,11 +776,11 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, o
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if _, err := copyWithBuffer(file, reader); err != nil {
 | 
							if err := copyWithBuffer(file, reader); err != nil {
 | 
				
			||||||
			file.Close()
 | 
								_ = file.Close()
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		file.Close()
 | 
							_ = file.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case tar.TypeBlock, tar.TypeChar:
 | 
						case tar.TypeBlock, tar.TypeChar:
 | 
				
			||||||
		if inUserns { // cannot create devices in a userns
 | 
							if inUserns { // cannot create devices in a userns
 | 
				
			||||||
@@ -1438,7 +1436,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
 | 
				
			|||||||
			if err := tw.WriteHeader(hdr); err != nil {
 | 
								if err := tw.WriteHeader(hdr); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if _, err := copyWithBuffer(tw, srcF); err != nil {
 | 
								if err := copyWithBuffer(tw, srcF); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										65
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -20,7 +20,7 @@ func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type overlayWhiteoutConverter struct{}
 | 
					type overlayWhiteoutConverter struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, err error) {
 | 
					func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, _ error) {
 | 
				
			||||||
	// convert whiteouts to AUFS format
 | 
						// convert whiteouts to AUFS format
 | 
				
			||||||
	if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 {
 | 
						if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 {
 | 
				
			||||||
		// we just rename the file and make it normal
 | 
							// we just rename the file and make it normal
 | 
				
			||||||
@@ -31,38 +31,41 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
 | 
				
			|||||||
		hdr.Size = 0
 | 
							hdr.Size = 0
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if fi.Mode()&os.ModeDir != 0 {
 | 
						if fi.Mode()&os.ModeDir == 0 {
 | 
				
			||||||
		opaqueXattrName := "trusted.overlay.opaque"
 | 
							// FIXME(thaJeztah): return a sentinel error instead of nil, nil
 | 
				
			||||||
		if userns.RunningInUserNS() {
 | 
							return nil, nil
 | 
				
			||||||
			opaqueXattrName = "user.overlay.opaque"
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// convert opaque dirs to AUFS format by writing an empty file with the prefix
 | 
					 | 
				
			||||||
		opaque, err := lgetxattr(path, opaqueXattrName)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(opaque) == 1 && opaque[0] == 'y' {
 | 
					 | 
				
			||||||
			delete(hdr.PAXRecords, paxSchilyXattr+opaqueXattrName)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// create a header for the whiteout file
 | 
					 | 
				
			||||||
			// it should inherit some properties from the parent, but be a regular file
 | 
					 | 
				
			||||||
			wo = &tar.Header{
 | 
					 | 
				
			||||||
				Typeflag:   tar.TypeReg,
 | 
					 | 
				
			||||||
				Mode:       hdr.Mode & int64(os.ModePerm),
 | 
					 | 
				
			||||||
				Name:       filepath.Join(hdr.Name, WhiteoutOpaqueDir), // #nosec G305 -- An archive is being created, not extracted.
 | 
					 | 
				
			||||||
				Size:       0,
 | 
					 | 
				
			||||||
				Uid:        hdr.Uid,
 | 
					 | 
				
			||||||
				Uname:      hdr.Uname,
 | 
					 | 
				
			||||||
				Gid:        hdr.Gid,
 | 
					 | 
				
			||||||
				Gname:      hdr.Gname,
 | 
					 | 
				
			||||||
				AccessTime: hdr.AccessTime,
 | 
					 | 
				
			||||||
				ChangeTime: hdr.ChangeTime,
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return
 | 
						opaqueXattrName := "trusted.overlay.opaque"
 | 
				
			||||||
 | 
						if userns.RunningInUserNS() {
 | 
				
			||||||
 | 
							opaqueXattrName = "user.overlay.opaque"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// convert opaque dirs to AUFS format by writing an empty file with the prefix
 | 
				
			||||||
 | 
						opaque, err := lgetxattr(path, opaqueXattrName)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(opaque) != 1 || opaque[0] != 'y' {
 | 
				
			||||||
 | 
							// FIXME(thaJeztah): return a sentinel error instead of nil, nil
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						delete(hdr.PAXRecords, paxSchilyXattr+opaqueXattrName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create a header for the whiteout file
 | 
				
			||||||
 | 
						// it should inherit some properties from the parent, but be a regular file
 | 
				
			||||||
 | 
						return &tar.Header{
 | 
				
			||||||
 | 
							Typeflag:   tar.TypeReg,
 | 
				
			||||||
 | 
							Mode:       hdr.Mode & int64(os.ModePerm),
 | 
				
			||||||
 | 
							Name:       filepath.Join(hdr.Name, WhiteoutOpaqueDir), // #nosec G305 -- An archive is being created, not extracted.
 | 
				
			||||||
 | 
							Size:       0,
 | 
				
			||||||
 | 
							Uid:        hdr.Uid,
 | 
				
			||||||
 | 
							Uname:      hdr.Uname,
 | 
				
			||||||
 | 
							Gid:        hdr.Gid,
 | 
				
			||||||
 | 
							Gname:      hdr.Gname,
 | 
				
			||||||
 | 
							AccessTime: hdr.AccessTime,
 | 
				
			||||||
 | 
							ChangeTime: hdr.ChangeTime,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) {
 | 
					func (c overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -73,14 +73,13 @@ func statUnix(fi os.FileInfo, hdr *tar.Header) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getInodeFromStat(stat interface{}) (inode uint64, err error) {
 | 
					func getInodeFromStat(stat interface{}) (uint64, error) {
 | 
				
			||||||
	s, ok := stat.(*syscall.Stat_t)
 | 
						s, ok := stat.(*syscall.Stat_t)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
	if ok {
 | 
							// FIXME(thaJeztah): this should likely return an error; see https://github.com/moby/moby/pull/49493#discussion_r1979152897
 | 
				
			||||||
		inode = s.Ino
 | 
							return 0, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return s.Ino, nil
 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
 | 
					func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -48,9 +48,9 @@ func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getInodeFromStat(stat interface{}) (inode uint64, err error) {
 | 
					func getInodeFromStat(stat interface{}) (uint64, error) {
 | 
				
			||||||
	// do nothing. no notion of Inode in stat on Windows
 | 
						// do nothing. no notion of Inode in stat on Windows
 | 
				
			||||||
	return
 | 
						return 0, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
 | 
					// handleTarTypeBlockCharFifo is an OS-specific helper function used by
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/docker/docker/pkg/archive/changes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/docker/docker/pkg/archive/changes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -83,7 +83,7 @@ func aufsMetadataSkip(path string) (skip bool, err error) {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		skip = true
 | 
							skip = true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return skip, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func aufsDeletedFile(root, path string, fi os.FileInfo) (string, error) {
 | 
					func aufsDeletedFile(root, path string, fi os.FileInfo) (string, error) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								vendor/github.com/docker/docker/pkg/archive/copy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/docker/docker/pkg/archive/copy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -25,11 +25,11 @@ var copyPool = sync.Pool{
 | 
				
			|||||||
	New: func() interface{} { s := make([]byte, 32*1024); return &s },
 | 
						New: func() interface{} { s := make([]byte, 32*1024); return &s },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func copyWithBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
 | 
					func copyWithBuffer(dst io.Writer, src io.Reader) error {
 | 
				
			||||||
	buf := copyPool.Get().(*[]byte)
 | 
						buf := copyPool.Get().(*[]byte)
 | 
				
			||||||
	written, err = io.CopyBuffer(dst, src, *buf)
 | 
						_, err := io.CopyBuffer(dst, src, *buf)
 | 
				
			||||||
	copyPool.Put(buf)
 | 
						copyPool.Put(buf)
 | 
				
			||||||
	return
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PreserveTrailingDotOrSeparator returns the given cleaned path (after
 | 
					// PreserveTrailingDotOrSeparator returns the given cleaned path (after
 | 
				
			||||||
@@ -105,13 +105,13 @@ func TarResource(sourceInfo CopyInfo) (content io.ReadCloser, err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// TarResourceRebase is like TarResource but renames the first path element of
 | 
					// TarResourceRebase is like TarResource but renames the first path element of
 | 
				
			||||||
// items in the resulting tar archive to match the given rebaseName if not "".
 | 
					// items in the resulting tar archive to match the given rebaseName if not "".
 | 
				
			||||||
func TarResourceRebase(sourcePath, rebaseName string) (content io.ReadCloser, err error) {
 | 
					func TarResourceRebase(sourcePath, rebaseName string) (content io.ReadCloser, _ error) {
 | 
				
			||||||
	sourcePath = normalizePath(sourcePath)
 | 
						sourcePath = normalizePath(sourcePath)
 | 
				
			||||||
	if _, err = os.Lstat(sourcePath); err != nil {
 | 
						if _, err := os.Lstat(sourcePath); err != nil {
 | 
				
			||||||
		// Catches the case where the source does not exist or is not a
 | 
							// Catches the case where the source does not exist or is not a
 | 
				
			||||||
		// directory if asserted to be a directory, as this also causes an
 | 
							// directory if asserted to be a directory, as this also causes an
 | 
				
			||||||
		// error.
 | 
							// error.
 | 
				
			||||||
		return
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Separate the source path between its directory and
 | 
						// Separate the source path between its directory and
 | 
				
			||||||
@@ -442,11 +442,12 @@ func CopyTo(content io.Reader, srcInfo CopyInfo, dstPath string) error {
 | 
				
			|||||||
// whether to follow symbol link or not, if followLink is true, resolvedPath will return
 | 
					// whether to follow symbol link or not, if followLink is true, resolvedPath will return
 | 
				
			||||||
// link target of any symbol link file, else it will only resolve symlink of directory
 | 
					// link target of any symbol link file, else it will only resolve symlink of directory
 | 
				
			||||||
// but return symbol link file itself without resolving.
 | 
					// but return symbol link file itself without resolving.
 | 
				
			||||||
func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseName string, err error) {
 | 
					func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseName string, _ error) {
 | 
				
			||||||
	if followLink {
 | 
						if followLink {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
		resolvedPath, err = filepath.EvalSymlinks(path)
 | 
							resolvedPath, err = filepath.EvalSymlinks(path)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return
 | 
								return "", "", err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		resolvedPath, rebaseName = GetRebaseName(path, resolvedPath)
 | 
							resolvedPath, rebaseName = GetRebaseName(path, resolvedPath)
 | 
				
			||||||
@@ -454,10 +455,9 @@ func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseNa
 | 
				
			|||||||
		dirPath, basePath := filepath.Split(path)
 | 
							dirPath, basePath := filepath.Split(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// if not follow symbol link, then resolve symbol link of parent dir
 | 
							// if not follow symbol link, then resolve symbol link of parent dir
 | 
				
			||||||
		var resolvedDirPath string
 | 
							resolvedDirPath, err := filepath.EvalSymlinks(dirPath)
 | 
				
			||||||
		resolvedDirPath, err = filepath.EvalSymlinks(dirPath)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return
 | 
								return "", "", err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// resolvedDirPath will have been cleaned (no trailing path separators) so
 | 
							// resolvedDirPath will have been cleaned (no trailing path separators) so
 | 
				
			||||||
		// we can manually join it with the base path element.
 | 
							// we can manually join it with the base path element.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								vendor/github.com/docker/docker/pkg/archive/time_nonwindows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/docker/docker/pkg/archive/time_nonwindows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -17,12 +17,13 @@ func chtimes(name string, atime time.Time, mtime time.Time) error {
 | 
				
			|||||||
	return os.Chtimes(name, atime, mtime)
 | 
						return os.Chtimes(name, atime, mtime)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func timeToTimespec(time time.Time) (ts unix.Timespec) {
 | 
					func timeToTimespec(time time.Time) unix.Timespec {
 | 
				
			||||||
	if time.IsZero() {
 | 
						if time.IsZero() {
 | 
				
			||||||
		// Return UTIME_OMIT special value
 | 
							// Return UTIME_OMIT special value
 | 
				
			||||||
		ts.Sec = 0
 | 
							return unix.Timespec{
 | 
				
			||||||
		ts.Nsec = (1 << 30) - 2
 | 
								Sec:  0,
 | 
				
			||||||
		return
 | 
								Nsec: (1 << 30) - 2,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return unix.NsecToTimespec(time.UnixNano())
 | 
						return unix.NsecToTimespec(time.UnixNano())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								vendor/github.com/docker/docker/pkg/archive/wrap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/docker/docker/pkg/archive/wrap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -45,8 +45,8 @@ func Generate(input ...string) (io.Reader, error) {
 | 
				
			|||||||
	return buf, nil
 | 
						return buf, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func parseStringPairs(input ...string) (output [][2]string) {
 | 
					func parseStringPairs(input ...string) [][2]string {
 | 
				
			||||||
	output = make([][2]string, 0, len(input)/2+1)
 | 
						output := make([][2]string, 0, len(input)/2+1)
 | 
				
			||||||
	for i := 0; i < len(input); i += 2 {
 | 
						for i := 0; i < len(input); i += 2 {
 | 
				
			||||||
		var pair [2]string
 | 
							var pair [2]string
 | 
				
			||||||
		pair[0] = input[i]
 | 
							pair[0] = input[i]
 | 
				
			||||||
@@ -55,5 +55,5 @@ func parseStringPairs(input ...string) (output [][2]string) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		output = append(output, pair)
 | 
							output = append(output, pair)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return output
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								vendor/github.com/docker/docker/pkg/atomicwriter/atomicwriter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/docker/docker/pkg/atomicwriter/atomicwriter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -11,12 +11,12 @@ import (
 | 
				
			|||||||
// destination path. Writing and closing concurrently is not allowed.
 | 
					// destination path. Writing and closing concurrently is not allowed.
 | 
				
			||||||
// NOTE: umask is not considered for the file's permissions.
 | 
					// NOTE: umask is not considered for the file's permissions.
 | 
				
			||||||
func New(filename string, perm os.FileMode) (io.WriteCloser, error) {
 | 
					func New(filename string, perm os.FileMode) (io.WriteCloser, error) {
 | 
				
			||||||
	f, err := os.CreateTemp(filepath.Dir(filename), ".tmp-"+filepath.Base(filename))
 | 
						abspath, err := filepath.Abs(filename)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	abspath, err := filepath.Abs(filename)
 | 
						f, err := os.CreateTemp(filepath.Dir(abspath), ".tmp-"+filepath.Base(filename))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -43,9 +43,9 @@ type stdWriter struct {
 | 
				
			|||||||
// It inserts the prefix header before the buffer,
 | 
					// It inserts the prefix header before the buffer,
 | 
				
			||||||
// so stdcopy.StdCopy knows where to multiplex the output.
 | 
					// so stdcopy.StdCopy knows where to multiplex the output.
 | 
				
			||||||
// It makes stdWriter to implement io.Writer.
 | 
					// It makes stdWriter to implement io.Writer.
 | 
				
			||||||
func (w *stdWriter) Write(p []byte) (n int, err error) {
 | 
					func (w *stdWriter) Write(p []byte) (int, error) {
 | 
				
			||||||
	if w == nil || w.Writer == nil {
 | 
						if w == nil || w.Writer == nil {
 | 
				
			||||||
		return 0, errors.New("Writer not instantiated")
 | 
							return 0, errors.New("writer not instantiated")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if p == nil {
 | 
						if p == nil {
 | 
				
			||||||
		return 0, nil
 | 
							return 0, nil
 | 
				
			||||||
@@ -57,7 +57,7 @@ func (w *stdWriter) Write(p []byte) (n int, err error) {
 | 
				
			|||||||
	buf.Write(header[:])
 | 
						buf.Write(header[:])
 | 
				
			||||||
	buf.Write(p)
 | 
						buf.Write(p)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	n, err = w.Writer.Write(buf.Bytes())
 | 
						n, err := w.Writer.Write(buf.Bytes())
 | 
				
			||||||
	n -= stdWriterPrefixLen
 | 
						n -= stdWriterPrefixLen
 | 
				
			||||||
	if n < 0 {
 | 
						if n < 0 {
 | 
				
			||||||
		n = 0
 | 
							n = 0
 | 
				
			||||||
@@ -65,7 +65,7 @@ func (w *stdWriter) Write(p []byte) (n int, err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	buf.Reset()
 | 
						buf.Reset()
 | 
				
			||||||
	bufPool.Put(buf)
 | 
						bufPool.Put(buf)
 | 
				
			||||||
	return
 | 
						return n, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewStdWriter instantiates a new Writer.
 | 
					// NewStdWriter instantiates a new Writer.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								vendor/github.com/docker/docker/registry/auth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/docker/docker/registry/auth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -66,13 +66,13 @@ func (scs staticCredentialStore) SetRefreshToken(*url.URL, string, string) {
 | 
				
			|||||||
// loginV2 tries to login to the v2 registry server. The given registry
 | 
					// loginV2 tries to login to the v2 registry server. The given registry
 | 
				
			||||||
// endpoint will be pinged to get authorization challenges. These challenges
 | 
					// endpoint will be pinged to get authorization challenges. These challenges
 | 
				
			||||||
// will be used to authenticate against the registry to validate credentials.
 | 
					// will be used to authenticate against the registry to validate credentials.
 | 
				
			||||||
func loginV2(authConfig *registry.AuthConfig, endpoint APIEndpoint, userAgent string) (status string, token string, _ error) {
 | 
					func loginV2(authConfig *registry.AuthConfig, endpoint APIEndpoint, userAgent string) (token string, _ error) {
 | 
				
			||||||
	endpointStr := strings.TrimRight(endpoint.URL.String(), "/") + "/v2/"
 | 
						endpointStr := strings.TrimRight(endpoint.URL.String(), "/") + "/v2/"
 | 
				
			||||||
	log.G(context.TODO()).Debugf("attempting v2 login to registry endpoint %s", endpointStr)
 | 
						log.G(context.TODO()).Debugf("attempting v2 login to registry endpoint %s", endpointStr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req, err := http.NewRequest(http.MethodGet, endpointStr, nil)
 | 
						req, err := http.NewRequest(http.MethodGet, endpointStr, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
@@ -84,22 +84,22 @@ func loginV2(authConfig *registry.AuthConfig, endpoint APIEndpoint, userAgent st
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	loginClient, err := v2AuthHTTPClient(endpoint.URL, authTrans, modifiers, creds, nil)
 | 
						loginClient, err := v2AuthHTTPClient(endpoint.URL, authTrans, modifiers, creds, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resp, err := loginClient.Do(req)
 | 
						resp, err := loginClient.Do(req)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		err = translateV2AuthError(err)
 | 
							err = translateV2AuthError(err)
 | 
				
			||||||
		return "", "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer resp.Body.Close()
 | 
						defer resp.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if resp.StatusCode == http.StatusOK {
 | 
						if resp.StatusCode != http.StatusOK {
 | 
				
			||||||
		return "Login Succeeded", credentialAuthConfig.IdentityToken, nil
 | 
							// TODO(dmcgowan): Attempt to further interpret result, status code and error code string
 | 
				
			||||||
 | 
							return "", errors.Errorf("login attempt to %s failed with status: %d %s", endpointStr, resp.StatusCode, http.StatusText(resp.StatusCode))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO(dmcgowan): Attempt to further interpret result, status code and error code string
 | 
						return credentialAuthConfig.IdentityToken, nil
 | 
				
			||||||
	return "", "", errors.Errorf("login attempt to %s failed with status: %d %s", endpointStr, resp.StatusCode, http.StatusText(resp.StatusCode))
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func v2AuthHTTPClient(endpoint *url.URL, authTransport http.RoundTripper, modifiers []transport.RequestModifier, creds auth.CredentialStore, scopes []auth.Scope) (*http.Client, error) {
 | 
					func v2AuthHTTPClient(endpoint *url.URL, authTransport http.RoundTripper, modifiers []transport.RequestModifier, creds auth.CredentialStore, scopes []auth.Scope) (*http.Client, error) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										168
									
								
								vendor/github.com/docker/docker/registry/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										168
									
								
								vendor/github.com/docker/docker/registry/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,13 +4,17 @@ import (
 | 
				
			|||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/log"
 | 
						"github.com/containerd/log"
 | 
				
			||||||
	"github.com/distribution/reference"
 | 
						"github.com/distribution/reference"
 | 
				
			||||||
	"github.com/docker/docker/api/types/registry"
 | 
						"github.com/docker/docker/api/types/registry"
 | 
				
			||||||
	"github.com/docker/docker/internal/lazyregexp"
 | 
						"github.com/docker/docker/internal/lazyregexp"
 | 
				
			||||||
 | 
						"github.com/docker/docker/pkg/homedir"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ServiceOptions holds command line options.
 | 
					// ServiceOptions holds command line options.
 | 
				
			||||||
@@ -56,26 +60,52 @@ var (
 | 
				
			|||||||
		Host:   DefaultRegistryHost,
 | 
							Host:   DefaultRegistryHost,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	emptyServiceConfig, _ = newServiceConfig(ServiceOptions{})
 | 
						validHostPortRegex = lazyregexp.New(`^` + reference.DomainRegexp.String() + `$`)
 | 
				
			||||||
	validHostPortRegex    = lazyregexp.New(`^` + reference.DomainRegexp.String() + `$`)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// certsDir is used to override defaultCertsDir.
 | 
						// certsDir is used to override defaultCertsDir when running with rootlessKit.
 | 
				
			||||||
	certsDir string
 | 
						//
 | 
				
			||||||
 | 
						// TODO(thaJeztah): change to a sync.OnceValue once we remove [SetCertsDir]
 | 
				
			||||||
 | 
						// TODO(thaJeztah): certsDir should not be a package variable, but stored in our config, and passed when needed.
 | 
				
			||||||
 | 
						setCertsDirOnce sync.Once
 | 
				
			||||||
 | 
						certsDir        string
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func setCertsDir(dir string) string {
 | 
				
			||||||
 | 
						setCertsDirOnce.Do(func() {
 | 
				
			||||||
 | 
							if dir != "" {
 | 
				
			||||||
 | 
								certsDir = dir
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if os.Getenv("ROOTLESSKIT_STATE_DIR") != "" {
 | 
				
			||||||
 | 
								// Configure registry.CertsDir() when running in rootless-mode
 | 
				
			||||||
 | 
								// This is the equivalent of [rootless.RunningWithRootlessKit],
 | 
				
			||||||
 | 
								// but inlining it to prevent adding that as a dependency
 | 
				
			||||||
 | 
								// for docker/cli.
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								// [rootless.RunningWithRootlessKit]: https://github.com/moby/moby/blob/b4bdf12daec84caaf809a639f923f7370d4926ad/pkg/rootless/rootless.go#L5-L8
 | 
				
			||||||
 | 
								if configHome, _ := homedir.GetConfigHome(); configHome != "" {
 | 
				
			||||||
 | 
									certsDir = filepath.Join(configHome, "docker/certs.d")
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							certsDir = defaultCertsDir
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return certsDir
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetCertsDir allows the default certs directory to be changed. This function
 | 
					// SetCertsDir allows the default certs directory to be changed. This function
 | 
				
			||||||
// is used at daemon startup to set the correct location when running in
 | 
					// is used at daemon startup to set the correct location when running in
 | 
				
			||||||
// rootless mode.
 | 
					// rootless mode.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Deprecated: the cert-directory is now automatically selected when running with rootlessKit, and should no longer be set manually.
 | 
				
			||||||
func SetCertsDir(path string) {
 | 
					func SetCertsDir(path string) {
 | 
				
			||||||
	certsDir = path
 | 
						setCertsDir(path)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CertsDir is the directory where certificates are stored.
 | 
					// CertsDir is the directory where certificates are stored.
 | 
				
			||||||
func CertsDir() string {
 | 
					func CertsDir() string {
 | 
				
			||||||
	if certsDir != "" {
 | 
						// call setCertsDir with an empty path to synchronise with [SetCertsDir]
 | 
				
			||||||
		return certsDir
 | 
						return setCertsDir("")
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return defaultCertsDir
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// newServiceConfig returns a new instance of ServiceConfig
 | 
					// newServiceConfig returns a new instance of ServiceConfig
 | 
				
			||||||
@@ -181,7 +211,7 @@ skip:
 | 
				
			|||||||
			// Assume `host:port` if not CIDR.
 | 
								// Assume `host:port` if not CIDR.
 | 
				
			||||||
			indexConfigs[r] = ®istry.IndexInfo{
 | 
								indexConfigs[r] = ®istry.IndexInfo{
 | 
				
			||||||
				Name:     r,
 | 
									Name:     r,
 | 
				
			||||||
				Mirrors:  make([]string, 0),
 | 
									Mirrors:  []string{},
 | 
				
			||||||
				Secure:   false,
 | 
									Secure:   false,
 | 
				
			||||||
				Official: false,
 | 
									Official: false,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -288,16 +318,22 @@ func ValidateMirror(val string) (string, error) {
 | 
				
			|||||||
// ValidateIndexName validates an index name. It is used by the daemon to
 | 
					// ValidateIndexName validates an index name. It is used by the daemon to
 | 
				
			||||||
// validate the daemon configuration.
 | 
					// validate the daemon configuration.
 | 
				
			||||||
func ValidateIndexName(val string) (string, error) {
 | 
					func ValidateIndexName(val string) (string, error) {
 | 
				
			||||||
	// TODO: upstream this to check to reference package
 | 
						val = normalizeIndexName(val)
 | 
				
			||||||
	if val == "index.docker.io" {
 | 
					 | 
				
			||||||
		val = "docker.io"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if strings.HasPrefix(val, "-") || strings.HasSuffix(val, "-") {
 | 
						if strings.HasPrefix(val, "-") || strings.HasSuffix(val, "-") {
 | 
				
			||||||
		return "", invalidParamf("invalid index name (%s). Cannot begin or end with a hyphen", val)
 | 
							return "", invalidParamf("invalid index name (%s). Cannot begin or end with a hyphen", val)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return val, nil
 | 
						return val, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func normalizeIndexName(val string) string {
 | 
				
			||||||
 | 
						// TODO(thaJeztah): consider normalizing other known options, such as "(https://)registry-1.docker.io", "https://index.docker.io/v1/".
 | 
				
			||||||
 | 
						// TODO: upstream this to check to reference package
 | 
				
			||||||
 | 
						if val == "index.docker.io" {
 | 
				
			||||||
 | 
							return "docker.io"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return val
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func hasScheme(reposName string) bool {
 | 
					func hasScheme(reposName string) bool {
 | 
				
			||||||
	return strings.Contains(reposName, "://")
 | 
						return strings.Contains(reposName, "://")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -327,25 +363,20 @@ func validateHostPort(s string) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// newIndexInfo returns IndexInfo configuration from indexName
 | 
					// newIndexInfo returns IndexInfo configuration from indexName
 | 
				
			||||||
func newIndexInfo(config *serviceConfig, indexName string) (*registry.IndexInfo, error) {
 | 
					func newIndexInfo(config *serviceConfig, indexName string) *registry.IndexInfo {
 | 
				
			||||||
	var err error
 | 
						indexName = normalizeIndexName(indexName)
 | 
				
			||||||
	indexName, err = ValidateIndexName(indexName)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Return any configured index info, first.
 | 
						// Return any configured index info, first.
 | 
				
			||||||
	if index, ok := config.IndexConfigs[indexName]; ok {
 | 
						if index, ok := config.IndexConfigs[indexName]; ok {
 | 
				
			||||||
		return index, nil
 | 
							return index
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Construct a non-configured index info.
 | 
						// Construct a non-configured index info.
 | 
				
			||||||
	return ®istry.IndexInfo{
 | 
						return ®istry.IndexInfo{
 | 
				
			||||||
		Name:     indexName,
 | 
							Name:    indexName,
 | 
				
			||||||
		Mirrors:  make([]string, 0),
 | 
							Mirrors: []string{},
 | 
				
			||||||
		Secure:   config.isSecureIndex(indexName),
 | 
							Secure:  config.isSecureIndex(indexName),
 | 
				
			||||||
		Official: false,
 | 
						}
 | 
				
			||||||
	}, nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetAuthConfigKey special-cases using the full index address of the official
 | 
					// GetAuthConfigKey special-cases using the full index address of the official
 | 
				
			||||||
@@ -358,18 +389,22 @@ func GetAuthConfigKey(index *registry.IndexInfo) string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// newRepositoryInfo validates and breaks down a repository name into a RepositoryInfo
 | 
					// newRepositoryInfo validates and breaks down a repository name into a RepositoryInfo
 | 
				
			||||||
func newRepositoryInfo(config *serviceConfig, name reference.Named) (*RepositoryInfo, error) {
 | 
					func newRepositoryInfo(config *serviceConfig, name reference.Named) *RepositoryInfo {
 | 
				
			||||||
	index, err := newIndexInfo(config, reference.Domain(name))
 | 
						index := newIndexInfo(config, reference.Domain(name))
 | 
				
			||||||
	if err != nil {
 | 
						var officialRepo bool
 | 
				
			||||||
		return nil, err
 | 
						if index.Official {
 | 
				
			||||||
 | 
							// RepositoryInfo.Official indicates whether the image repository
 | 
				
			||||||
 | 
							// is an official (docker library official images) repository.
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							// We only need to check this if the image-repository is on Docker Hub.
 | 
				
			||||||
 | 
							officialRepo = !strings.ContainsRune(reference.FamiliarName(name), '/')
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	official := !strings.ContainsRune(reference.FamiliarName(name), '/')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &RepositoryInfo{
 | 
						return &RepositoryInfo{
 | 
				
			||||||
		Name:     reference.TrimNamed(name),
 | 
							Name:     reference.TrimNamed(name),
 | 
				
			||||||
		Index:    index,
 | 
							Index:    index,
 | 
				
			||||||
		Official: official,
 | 
							Official: officialRepo,
 | 
				
			||||||
	}, nil
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ParseRepositoryInfo performs the breakdown of a repository name into a
 | 
					// ParseRepositoryInfo performs the breakdown of a repository name into a
 | 
				
			||||||
@@ -377,5 +412,70 @@ func newRepositoryInfo(config *serviceConfig, name reference.Named) (*Repository
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
// It is used by the Docker cli to interact with registry-related endpoints.
 | 
					// It is used by the Docker cli to interact with registry-related endpoints.
 | 
				
			||||||
func ParseRepositoryInfo(reposName reference.Named) (*RepositoryInfo, error) {
 | 
					func ParseRepositoryInfo(reposName reference.Named) (*RepositoryInfo, error) {
 | 
				
			||||||
	return newRepositoryInfo(emptyServiceConfig, reposName)
 | 
						indexName := normalizeIndexName(reference.Domain(reposName))
 | 
				
			||||||
 | 
						if indexName == IndexName {
 | 
				
			||||||
 | 
							officialRepo := !strings.ContainsRune(reference.FamiliarName(reposName), '/')
 | 
				
			||||||
 | 
							return &RepositoryInfo{
 | 
				
			||||||
 | 
								Name: reference.TrimNamed(reposName),
 | 
				
			||||||
 | 
								Index: ®istry.IndexInfo{
 | 
				
			||||||
 | 
									Name:     IndexName,
 | 
				
			||||||
 | 
									Mirrors:  []string{},
 | 
				
			||||||
 | 
									Secure:   true,
 | 
				
			||||||
 | 
									Official: true,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Official: officialRepo,
 | 
				
			||||||
 | 
							}, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						insecure := false
 | 
				
			||||||
 | 
						if isInsecure(indexName) {
 | 
				
			||||||
 | 
							insecure = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &RepositoryInfo{
 | 
				
			||||||
 | 
							Name: reference.TrimNamed(reposName),
 | 
				
			||||||
 | 
							Index: ®istry.IndexInfo{
 | 
				
			||||||
 | 
								Name:    indexName,
 | 
				
			||||||
 | 
								Mirrors: []string{},
 | 
				
			||||||
 | 
								Secure:  !insecure,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// isInsecure is used to detect whether a registry domain or IP-address is allowed
 | 
				
			||||||
 | 
					// to use an insecure (non-TLS, or self-signed cert) connection according to the
 | 
				
			||||||
 | 
					// defaults, which allows for insecure connections with registries running on a
 | 
				
			||||||
 | 
					// loopback address ("localhost", "::1/128", "127.0.0.0/8").
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// It is used in situations where we don't have access to the daemon's configuration,
 | 
				
			||||||
 | 
					// for example, when used from the client / CLI.
 | 
				
			||||||
 | 
					func isInsecure(hostNameOrIP string) bool {
 | 
				
			||||||
 | 
						// Attempt to strip port if present; this also strips brackets for
 | 
				
			||||||
 | 
						// IPv6 addresses with a port (e.g. "[::1]:5000").
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// This is best-effort; we'll continue using the address as-is if it fails.
 | 
				
			||||||
 | 
						if host, _, err := net.SplitHostPort(hostNameOrIP); err == nil {
 | 
				
			||||||
 | 
							hostNameOrIP = host
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if hostNameOrIP == "127.0.0.1" || hostNameOrIP == "::1" || strings.EqualFold(hostNameOrIP, "localhost") {
 | 
				
			||||||
 | 
							// Fast path; no need to resolve these, assuming nobody overrides
 | 
				
			||||||
 | 
							// "localhost" for anything else than a loopback address (sorry, not sorry).
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var addresses []net.IP
 | 
				
			||||||
 | 
						if ip := net.ParseIP(hostNameOrIP); ip != nil {
 | 
				
			||||||
 | 
							addresses = append(addresses, ip)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// Try to resolve the host's IP-addresses.
 | 
				
			||||||
 | 
							addrs, _ := lookupIP(hostNameOrIP)
 | 
				
			||||||
 | 
							addresses = append(addresses, addrs...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, addr := range addresses {
 | 
				
			||||||
 | 
							if addr.IsLoopback() {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										31
									
								
								vendor/github.com/docker/docker/registry/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/docker/docker/registry/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -8,7 +8,6 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/containerd/log"
 | 
						"github.com/containerd/log"
 | 
				
			||||||
@@ -18,7 +17,14 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// HostCertsDir returns the config directory for a specific host.
 | 
					// HostCertsDir returns the config directory for a specific host.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Deprecated: this function was only used internally, and will be removed in a future release.
 | 
				
			||||||
func HostCertsDir(hostname string) string {
 | 
					func HostCertsDir(hostname string) string {
 | 
				
			||||||
 | 
						return hostCertsDir(hostname)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// hostCertsDir returns the config directory for a specific host.
 | 
				
			||||||
 | 
					func hostCertsDir(hostname string) string {
 | 
				
			||||||
	return filepath.Join(CertsDir(), cleanPath(hostname))
 | 
						return filepath.Join(CertsDir(), cleanPath(hostname))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,11 +32,10 @@ func HostCertsDir(hostname string) string {
 | 
				
			|||||||
func newTLSConfig(hostname string, isSecure bool) (*tls.Config, error) {
 | 
					func newTLSConfig(hostname string, isSecure bool) (*tls.Config, error) {
 | 
				
			||||||
	// PreferredServerCipherSuites should have no effect
 | 
						// PreferredServerCipherSuites should have no effect
 | 
				
			||||||
	tlsConfig := tlsconfig.ServerDefault()
 | 
						tlsConfig := tlsconfig.ServerDefault()
 | 
				
			||||||
 | 
					 | 
				
			||||||
	tlsConfig.InsecureSkipVerify = !isSecure
 | 
						tlsConfig.InsecureSkipVerify = !isSecure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if isSecure && CertsDir() != "" {
 | 
						if isSecure {
 | 
				
			||||||
		hostDir := HostCertsDir(hostname)
 | 
							hostDir := hostCertsDir(hostname)
 | 
				
			||||||
		log.G(context.TODO()).Debugf("hostDir: %s", hostDir)
 | 
							log.G(context.TODO()).Debugf("hostDir: %s", hostDir)
 | 
				
			||||||
		if err := ReadCertsDirectory(tlsConfig, hostDir); err != nil {
 | 
							if err := ReadCertsDirectory(tlsConfig, hostDir); err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
@@ -59,7 +64,8 @@ func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, f := range fs {
 | 
						for _, f := range fs {
 | 
				
			||||||
		if strings.HasSuffix(f.Name(), ".crt") {
 | 
							switch filepath.Ext(f.Name()) {
 | 
				
			||||||
 | 
							case ".crt":
 | 
				
			||||||
			if tlsConfig.RootCAs == nil {
 | 
								if tlsConfig.RootCAs == nil {
 | 
				
			||||||
				systemPool, err := tlsconfig.SystemCertPool()
 | 
									systemPool, err := tlsconfig.SystemCertPool()
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
@@ -67,17 +73,17 @@ func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
				tlsConfig.RootCAs = systemPool
 | 
									tlsConfig.RootCAs = systemPool
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			log.G(context.TODO()).Debugf("crt: %s", filepath.Join(directory, f.Name()))
 | 
								fileName := filepath.Join(directory, f.Name())
 | 
				
			||||||
			data, err := os.ReadFile(filepath.Join(directory, f.Name()))
 | 
								log.G(context.TODO()).Debugf("crt: %s", fileName)
 | 
				
			||||||
 | 
								data, err := os.ReadFile(fileName)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			tlsConfig.RootCAs.AppendCertsFromPEM(data)
 | 
								tlsConfig.RootCAs.AppendCertsFromPEM(data)
 | 
				
			||||||
		}
 | 
							case ".cert":
 | 
				
			||||||
		if strings.HasSuffix(f.Name(), ".cert") {
 | 
					 | 
				
			||||||
			certName := f.Name()
 | 
								certName := f.Name()
 | 
				
			||||||
			keyName := certName[:len(certName)-5] + ".key"
 | 
								keyName := certName[:len(certName)-5] + ".key"
 | 
				
			||||||
			log.G(context.TODO()).Debugf("cert: %s", filepath.Join(directory, f.Name()))
 | 
								log.G(context.TODO()).Debugf("cert: %s", filepath.Join(directory, certName))
 | 
				
			||||||
			if !hasFile(fs, keyName) {
 | 
								if !hasFile(fs, keyName) {
 | 
				
			||||||
				return invalidParamf("missing key %s for client certificate %s. CA certificates must use the extension .crt", keyName, certName)
 | 
									return invalidParamf("missing key %s for client certificate %s. CA certificates must use the extension .crt", keyName, certName)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -86,11 +92,10 @@ func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error {
 | 
				
			|||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
 | 
								tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
 | 
				
			||||||
		}
 | 
							case ".key":
 | 
				
			||||||
		if strings.HasSuffix(f.Name(), ".key") {
 | 
					 | 
				
			||||||
			keyName := f.Name()
 | 
								keyName := f.Name()
 | 
				
			||||||
			certName := keyName[:len(keyName)-4] + ".cert"
 | 
								certName := keyName[:len(keyName)-4] + ".cert"
 | 
				
			||||||
			log.G(context.TODO()).Debugf("key: %s", filepath.Join(directory, f.Name()))
 | 
								log.G(context.TODO()).Debugf("key: %s", filepath.Join(directory, keyName))
 | 
				
			||||||
			if !hasFile(fs, certName) {
 | 
								if !hasFile(fs, certName) {
 | 
				
			||||||
				return invalidParamf("missing client certificate %s for key %s", certName, keyName)
 | 
									return invalidParamf("missing client certificate %s for key %s", certName, keyName)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								vendor/github.com/docker/docker/registry/search.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/docker/docker/registry/search.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -93,12 +93,8 @@ func (s *Service) searchUnfiltered(ctx context.Context, term string, limit int,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Search is a long-running operation, just lock s.config to avoid block others.
 | 
						// Search is a long-running operation, just lock s.config to avoid block others.
 | 
				
			||||||
	s.mu.RLock()
 | 
						s.mu.RLock()
 | 
				
			||||||
	index, err := newIndexInfo(s.config, indexName)
 | 
						index := newIndexInfo(s.config, indexName)
 | 
				
			||||||
	s.mu.RUnlock()
 | 
						s.mu.RUnlock()
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if index.Official {
 | 
						if index.Official {
 | 
				
			||||||
		// If pull "library/foo", it's stored locally under "foo"
 | 
							// If pull "library/foo", it's stored locally under "foo"
 | 
				
			||||||
		remoteName = strings.TrimPrefix(remoteName, "library/")
 | 
							remoteName = strings.TrimPrefix(remoteName, "library/")
 | 
				
			||||||
@@ -158,5 +154,24 @@ func splitReposSearchTerm(reposName string) (string, string) {
 | 
				
			|||||||
// for that.
 | 
					// for that.
 | 
				
			||||||
func ParseSearchIndexInfo(reposName string) (*registry.IndexInfo, error) {
 | 
					func ParseSearchIndexInfo(reposName string) (*registry.IndexInfo, error) {
 | 
				
			||||||
	indexName, _ := splitReposSearchTerm(reposName)
 | 
						indexName, _ := splitReposSearchTerm(reposName)
 | 
				
			||||||
	return newIndexInfo(emptyServiceConfig, indexName)
 | 
						indexName = normalizeIndexName(indexName)
 | 
				
			||||||
 | 
						if indexName == IndexName {
 | 
				
			||||||
 | 
							return ®istry.IndexInfo{
 | 
				
			||||||
 | 
								Name:     IndexName,
 | 
				
			||||||
 | 
								Mirrors:  []string{},
 | 
				
			||||||
 | 
								Secure:   true,
 | 
				
			||||||
 | 
								Official: true,
 | 
				
			||||||
 | 
							}, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						insecure := false
 | 
				
			||||||
 | 
						if isInsecure(indexName) {
 | 
				
			||||||
 | 
							insecure = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ®istry.IndexInfo{
 | 
				
			||||||
 | 
							Name:    indexName,
 | 
				
			||||||
 | 
							Mirrors: []string{},
 | 
				
			||||||
 | 
							Secure:  !insecure,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								vendor/github.com/docker/docker/registry/search_session.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/docker/docker/registry/search_session.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -83,12 +83,12 @@ type onEOFReader struct {
 | 
				
			|||||||
	Fn func()
 | 
						Fn func()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *onEOFReader) Read(p []byte) (n int, err error) {
 | 
					func (r *onEOFReader) Read(p []byte) (int, error) {
 | 
				
			||||||
	n, err = r.Rc.Read(p)
 | 
						n, err := r.Rc.Read(p)
 | 
				
			||||||
	if err == io.EOF {
 | 
						if err == io.EOF {
 | 
				
			||||||
		r.runFunc()
 | 
							r.runFunc()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return n, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Close closes the file and run the function.
 | 
					// Close closes the file and run the function.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								vendor/github.com/docker/docker/registry/service.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								vendor/github.com/docker/docker/registry/service.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -52,7 +52,7 @@ func (s *Service) ReplaceConfig(options ServiceOptions) (commit func(), err erro
 | 
				
			|||||||
// Auth contacts the public registry with the provided credentials,
 | 
					// Auth contacts the public registry with the provided credentials,
 | 
				
			||||||
// and returns OK if authentication was successful.
 | 
					// and returns OK if authentication was successful.
 | 
				
			||||||
// It can be used to verify the validity of a client's credentials.
 | 
					// It can be used to verify the validity of a client's credentials.
 | 
				
			||||||
func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, userAgent string) (status, token string, err error) {
 | 
					func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, userAgent string) (statusMessage, token string, _ error) {
 | 
				
			||||||
	// TODO Use ctx when searching for repositories
 | 
						// TODO Use ctx when searching for repositories
 | 
				
			||||||
	registryHostName := IndexHostname
 | 
						registryHostName := IndexHostname
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -77,19 +77,28 @@ func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, use
 | 
				
			|||||||
		return "", "", invalidParam(err)
 | 
							return "", "", invalidParam(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var lastErr error
 | 
				
			||||||
	for _, endpoint := range endpoints {
 | 
						for _, endpoint := range endpoints {
 | 
				
			||||||
		status, token, err = loginV2(authConfig, endpoint, userAgent)
 | 
							authToken, err := loginV2(authConfig, endpoint, userAgent)
 | 
				
			||||||
		if err == nil {
 | 
							if err != nil {
 | 
				
			||||||
			return
 | 
								if errdefs.IsUnauthorized(err) {
 | 
				
			||||||
 | 
									// Failed to authenticate; don't continue with (non-TLS) endpoints.
 | 
				
			||||||
 | 
									return "", "", err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Try next endpoint
 | 
				
			||||||
 | 
								log.G(ctx).WithFields(log.Fields{
 | 
				
			||||||
 | 
									"error":    err,
 | 
				
			||||||
 | 
									"endpoint": endpoint,
 | 
				
			||||||
 | 
								}).Infof("Error logging in to endpoint, trying next endpoint")
 | 
				
			||||||
 | 
								lastErr = err
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if errdefs.IsUnauthorized(err) {
 | 
					
 | 
				
			||||||
			// Failed to authenticate; don't continue with (non-TLS) endpoints.
 | 
							// TODO(thaJeztah): move the statusMessage to the API endpoint; we don't need to produce that here?
 | 
				
			||||||
			return status, token, err
 | 
							return "Login Succeeded", authToken, nil
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		log.G(ctx).WithError(err).Infof("Error logging in to endpoint, trying next endpoint")
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return "", "", err
 | 
						return "", "", lastErr
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ResolveRepository splits a repository name into its components
 | 
					// ResolveRepository splits a repository name into its components
 | 
				
			||||||
@@ -97,7 +106,8 @@ func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, use
 | 
				
			|||||||
func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
 | 
					func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
 | 
				
			||||||
	s.mu.RLock()
 | 
						s.mu.RLock()
 | 
				
			||||||
	defer s.mu.RUnlock()
 | 
						defer s.mu.RUnlock()
 | 
				
			||||||
	return newRepositoryInfo(s.config, name)
 | 
						// TODO(thaJeztah): remove error return as it's no longer used.
 | 
				
			||||||
 | 
						return newRepositoryInfo(s.config, name), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// APIEndpoint represents a remote API endpoint
 | 
					// APIEndpoint represents a remote API endpoint
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/docker/docker/registry/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/docker/docker/registry/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -13,6 +13,8 @@ type RepositoryInfo struct {
 | 
				
			|||||||
	// Official indicates whether the repository is considered official.
 | 
						// Official indicates whether the repository is considered official.
 | 
				
			||||||
	// If the registry is official, and the normalized name does not
 | 
						// If the registry is official, and the normalized name does not
 | 
				
			||||||
	// contain a '/' (e.g. "foo"), then it is considered an official repo.
 | 
						// contain a '/' (e.g. "foo"), then it is considered an official repo.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Deprecated: this field is no longer used and will be removed in the next release. The information captured in this field can be obtained from the [Name] field instead.
 | 
				
			||||||
	Official bool
 | 
						Official bool
 | 
				
			||||||
	// Class represents the class of the repository, such as "plugin"
 | 
						// Class represents the class of the repository, such as "plugin"
 | 
				
			||||||
	// or "image".
 | 
						// or "image".
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@@ -155,7 +155,7 @@ github.com/containerd/console
 | 
				
			|||||||
# github.com/containerd/containerd/api v1.8.0
 | 
					# github.com/containerd/containerd/api v1.8.0
 | 
				
			||||||
## explicit; go 1.21
 | 
					## explicit; go 1.21
 | 
				
			||||||
github.com/containerd/containerd/api/services/content/v1
 | 
					github.com/containerd/containerd/api/services/content/v1
 | 
				
			||||||
# github.com/containerd/containerd/v2 v2.0.3
 | 
					# github.com/containerd/containerd/v2 v2.0.4
 | 
				
			||||||
## explicit; go 1.22.0
 | 
					## explicit; go 1.22.0
 | 
				
			||||||
github.com/containerd/containerd/v2/core/content
 | 
					github.com/containerd/containerd/v2/core/content
 | 
				
			||||||
github.com/containerd/containerd/v2/core/content/proxy
 | 
					github.com/containerd/containerd/v2/core/content/proxy
 | 
				
			||||||
@@ -229,11 +229,10 @@ github.com/davecgh/go-spew/spew
 | 
				
			|||||||
# github.com/distribution/reference v0.6.0
 | 
					# github.com/distribution/reference v0.6.0
 | 
				
			||||||
## explicit; go 1.20
 | 
					## explicit; go 1.20
 | 
				
			||||||
github.com/distribution/reference
 | 
					github.com/distribution/reference
 | 
				
			||||||
# github.com/docker/cli v28.0.1+incompatible
 | 
					# github.com/docker/cli v28.0.2+incompatible
 | 
				
			||||||
## explicit
 | 
					## explicit
 | 
				
			||||||
github.com/docker/cli/cli
 | 
					github.com/docker/cli/cli
 | 
				
			||||||
github.com/docker/cli/cli-plugins/hooks
 | 
					github.com/docker/cli/cli-plugins/metadata
 | 
				
			||||||
github.com/docker/cli/cli-plugins/manager
 | 
					 | 
				
			||||||
github.com/docker/cli/cli-plugins/plugin
 | 
					github.com/docker/cli/cli-plugins/plugin
 | 
				
			||||||
github.com/docker/cli/cli-plugins/socket
 | 
					github.com/docker/cli/cli-plugins/socket
 | 
				
			||||||
github.com/docker/cli/cli/command
 | 
					github.com/docker/cli/cli/command
 | 
				
			||||||
@@ -252,6 +251,7 @@ github.com/docker/cli/cli/context/store
 | 
				
			|||||||
github.com/docker/cli/cli/debug
 | 
					github.com/docker/cli/cli/debug
 | 
				
			||||||
github.com/docker/cli/cli/flags
 | 
					github.com/docker/cli/cli/flags
 | 
				
			||||||
github.com/docker/cli/cli/hints
 | 
					github.com/docker/cli/cli/hints
 | 
				
			||||||
 | 
					github.com/docker/cli/cli/internal/jsonstream
 | 
				
			||||||
github.com/docker/cli/cli/manifest/store
 | 
					github.com/docker/cli/cli/manifest/store
 | 
				
			||||||
github.com/docker/cli/cli/manifest/types
 | 
					github.com/docker/cli/cli/manifest/types
 | 
				
			||||||
github.com/docker/cli/cli/registry/client
 | 
					github.com/docker/cli/cli/registry/client
 | 
				
			||||||
@@ -260,6 +260,7 @@ github.com/docker/cli/cli/trust
 | 
				
			|||||||
github.com/docker/cli/cli/version
 | 
					github.com/docker/cli/cli/version
 | 
				
			||||||
github.com/docker/cli/internal/tui
 | 
					github.com/docker/cli/internal/tui
 | 
				
			||||||
github.com/docker/cli/opts
 | 
					github.com/docker/cli/opts
 | 
				
			||||||
 | 
					github.com/docker/cli/opts/swarmopts
 | 
				
			||||||
github.com/docker/cli/pkg/kvfile
 | 
					github.com/docker/cli/pkg/kvfile
 | 
				
			||||||
github.com/docker/cli/templates
 | 
					github.com/docker/cli/templates
 | 
				
			||||||
# github.com/docker/cli-docs-tool v0.9.0
 | 
					# github.com/docker/cli-docs-tool v0.9.0
 | 
				
			||||||
@@ -283,7 +284,7 @@ github.com/docker/distribution/registry/client/transport
 | 
				
			|||||||
github.com/docker/distribution/registry/storage/cache
 | 
					github.com/docker/distribution/registry/storage/cache
 | 
				
			||||||
github.com/docker/distribution/registry/storage/cache/memory
 | 
					github.com/docker/distribution/registry/storage/cache/memory
 | 
				
			||||||
github.com/docker/distribution/uuid
 | 
					github.com/docker/distribution/uuid
 | 
				
			||||||
# github.com/docker/docker v28.0.1+incompatible
 | 
					# github.com/docker/docker v28.0.2+incompatible
 | 
				
			||||||
## explicit
 | 
					## explicit
 | 
				
			||||||
github.com/docker/docker/api
 | 
					github.com/docker/docker/api
 | 
				
			||||||
github.com/docker/docker/api/types
 | 
					github.com/docker/docker/api/types
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user