diff --git a/cli-plugins/plugin/plugin.go b/cli-plugins/plugin/plugin.go index 30940777d..58ee3b876 100644 --- a/cli-plugins/plugin/plugin.go +++ b/cli-plugins/plugin/plugin.go @@ -139,7 +139,7 @@ func withPluginClientConn(name string) command.CLIOption { if err != nil { return err } - apiClient, err := client.NewClientWithOpts(client.WithDialContext(helper.Dialer)) + apiClient, err := client.New(client.WithDialContext(helper.Dialer)) if err != nil { return err } diff --git a/cli/command/cli.go b/cli/command/cli.go index e102e8382..0a5a7d297 100644 --- a/cli/command/cli.go +++ b/cli/command/cli.go @@ -316,7 +316,7 @@ func newAPIClientFromEndpoint(ep docker.Endpoint, configFile *configfile.ConfigF opts = append(opts, withCustomHeaders) } opts = append(opts, extraOpts...) - return client.NewClientWithOpts(opts...) + return client.New(opts...) } func resolveDockerEndpoint(s store.Reader, contextName string) (docker.Endpoint, error) { diff --git a/cli/command/cli_test.go b/cli/command/cli_test.go index 000b26f1b..5213cbf28 100644 --- a/cli/command/cli_test.go +++ b/cli/command/cli_test.go @@ -292,7 +292,7 @@ func TestNewDockerCliAndOperators(t *testing.T) { func TestInitializeShouldAlwaysCreateTheContextStore(t *testing.T) { cli, err := NewDockerCli() assert.NilError(t, err) - apiClient, err := client.NewClientWithOpts() + apiClient, err := client.New() assert.NilError(t, err) assert.NilError(t, cli.Initialize(flags.NewClientOptions(), WithAPIClient(apiClient))) assert.Check(t, cli.ContextStore() != nil) diff --git a/cli/command/container/create.go b/cli/command/container/create.go index 03b7ac95f..815cdd450 100644 --- a/cli/command/container/create.go +++ b/cli/command/container/create.go @@ -135,9 +135,14 @@ func pullImage(ctx context.Context, dockerCli command.Cli, img string, options * return err } + var ociPlatforms []ocispec.Platform + if options.platform != "" { + // Already validated. + ociPlatforms = append(ociPlatforms, platforms.MustParse(options.platform)) + } resp, err := dockerCli.Client().ImageCreate(ctx, img, client.ImageCreateOptions{ RegistryAuth: encodedAuth, - Platform: options.platform, + Platforms: ociPlatforms, }) if err != nil { return err @@ -213,6 +218,14 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c namedRef reference.Named ) + // TODO(thaJeztah): add a platform option-type / flag-type. + if options.platform != "" { + _, err = platforms.Parse(options.platform) + if err != nil { + return "", err + } + } + containerIDFile, err := newCIDFile(hostConfig.ContainerIDFile) if err != nil { return "", err diff --git a/cli/command/container/opts.go b/cli/command/container/opts.go index c2253d6c0..05764ed45 100644 --- a/cli/command/container/opts.go +++ b/cli/command/container/opts.go @@ -885,10 +885,11 @@ func parseNetworkAttachmentOpt(ep opts.NetworkAttachmentOpts) (*network.Endpoint } } if ep.MacAddress != "" { - if _, err := net.ParseMAC(strings.TrimSpace(ep.MacAddress)); err != nil { + ma, err := net.ParseMAC(strings.TrimSpace(ep.MacAddress)) + if err != nil { return nil, fmt.Errorf("%s is not a valid mac address", ep.MacAddress) } - epConfig.MacAddress = ep.MacAddress + epConfig.MacAddress = network.HardwareAddr(ma) } return epConfig, nil } diff --git a/cli/command/container/opts_test.go b/cli/command/container/opts_test.go index 352c38d07..51a0e72b4 100644 --- a/cli/command/container/opts_test.go +++ b/cli/command/container/opts_test.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "net" "net/netip" "os" "runtime" @@ -20,6 +21,14 @@ import ( "gotest.tools/v3/skip" ) +func mustParseMAC(s string) networktypes.HardwareAddr { + mac, err := net.ParseMAC(s) + if err != nil { + panic(err) + } + return networktypes.HardwareAddr(mac) +} + func TestValidateAttach(t *testing.T) { valid := []string{ "stdin", @@ -353,7 +362,7 @@ func TestParseWithMacAddress(t *testing.T) { } _, hostConfig, nwConfig := mustParse(t, validMacAddress) defaultNw := hostConfig.NetworkMode.NetworkName() - if nwConfig.EndpointsConfig[defaultNw].MacAddress != "92:d0:c6:0a:29:33" { + if nwConfig.EndpointsConfig[defaultNw].MacAddress.String() != "92:d0:c6:0a:29:33" { t.Fatalf("Expected the default endpoint to have the MacAddress '92:d0:c6:0a:29:33' set, got '%v'", nwConfig.EndpointsConfig[defaultNw].MacAddress) } } @@ -650,7 +659,7 @@ func TestParseNetworkConfig(t *testing.T) { Aliases: []string{"web3"}, }, "net4": { - MacAddress: "02:32:1c:23:00:04", + MacAddress: mustParseMAC("02:32:1c:23:00:04"), IPAMConfig: &networktypes.EndpointIPAMConfig{ LinkLocalIPs: []netip.Addr{netip.MustParseAddr("169.254.169.254")}, }, @@ -672,7 +681,7 @@ func TestParseNetworkConfig(t *testing.T) { IPv6Address: netip.MustParseAddr("2001:db8::8822"), }, Aliases: []string{"web1", "web2"}, - MacAddress: "02:32:1c:23:00:04", + MacAddress: mustParseMAC("02:32:1c:23:00:04"), }, }, expectedHostCfg: container.HostConfig{NetworkMode: "net1"}, @@ -689,7 +698,7 @@ func TestParseNetworkConfig(t *testing.T) { expected: map[string]*networktypes.EndpointSettings{ "net1": { Aliases: []string{"foobar"}, - MacAddress: "52:0f:f3:dc:50:10", + MacAddress: mustParseMAC("52:0f:f3:dc:50:10"), }, }, expectedHostCfg: container.HostConfig{NetworkMode: "net1"}, diff --git a/cli/command/context/options.go b/cli/command/context/options.go index 804fdff9f..429f47cc4 100644 --- a/cli/command/context/options.go +++ b/cli/command/context/options.go @@ -123,7 +123,7 @@ func getDockerEndpoint(contextStore store.Reader, config map[string]string) (doc return docker.Endpoint{}, fmt.Errorf("invalid docker endpoint options: %w", err) } // FIXME(thaJeztah): this creates a new client (but discards it) only to validate the options; are the validation steps above not enough? - if _, err := client.NewClientWithOpts(opts...); err != nil { + if _, err := client.New(opts...); err != nil { return docker.Endpoint{}, fmt.Errorf("unable to apply docker endpoint options: %w", err) } return ep, nil diff --git a/cli/command/image/build.go b/cli/command/image/build.go index 9f4b25bac..8915308b3 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -11,6 +11,7 @@ import ( "path/filepath" "strings" + "github.com/containerd/platforms" "github.com/distribution/reference" "github.com/docker/cli-docs-tool/annotation" "github.com/docker/cli/cli" @@ -27,6 +28,7 @@ import ( "github.com/moby/moby/client" "github.com/moby/moby/client/pkg/progress" "github.com/moby/moby/client/pkg/streamformatter" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/spf13/cobra" ) @@ -190,6 +192,13 @@ func runBuild(ctx context.Context, dockerCli command.Cli, options buildOptions) remote string ) + if options.platform != "" { + _, err := platforms.Parse(options.platform) + if err != nil { + return err + } + } + contextType, err := build.DetectContextType(options.context) if err != nil { return err @@ -399,6 +408,12 @@ func validateTag(rawRepo string) (string, error) { func imageBuildOptions(dockerCli command.Cli, options buildOptions) client.ImageBuildOptions { configFile := dockerCli.ConfigFile() + + var buildPlatforms []ocispec.Platform + if options.platform != "" { + // Already validated. + buildPlatforms = append(buildPlatforms, platforms.MustParse(options.platform)) + } return client.ImageBuildOptions{ Version: buildtypes.BuilderV1, Memory: options.memory.Value(), @@ -426,6 +441,6 @@ func imageBuildOptions(dockerCli command.Cli, options buildOptions) client.Image Squash: options.squash, ExtraHosts: options.extraHosts.GetSlice(), Target: options.target, - Platform: options.platform, + Platforms: buildPlatforms, } } diff --git a/cli/command/image/import.go b/cli/command/image/import.go index 8af28c8de..b4be96405 100644 --- a/cli/command/image/import.go +++ b/cli/command/image/import.go @@ -5,12 +5,14 @@ import ( "os" "strings" + "github.com/containerd/platforms" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" "github.com/docker/cli/internal/jsonstream" dockeropts "github.com/docker/cli/opts" "github.com/moby/moby/client" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/spf13/cobra" ) @@ -82,10 +84,20 @@ func runImport(ctx context.Context, dockerCli command.Cli, options importOptions } } + // TODO(thaJeztah): add a platform option-type / flag-type. + var ociPlatform ocispec.Platform + if options.platform != "" { + var err error + ociPlatform, err = platforms.Parse(options.platform) + if err != nil { + return err + } + } + responseBody, err := dockerCli.Client().ImageImport(ctx, source, options.reference, client.ImageImportOptions{ Message: options.message, Changes: options.changes.GetSlice(), - Platform: options.platform, + Platform: ociPlatform, }) if err != nil { return err diff --git a/cli/command/image/pull.go b/cli/command/image/pull.go index 7df515f52..e076781bf 100644 --- a/cli/command/image/pull.go +++ b/cli/command/image/pull.go @@ -7,6 +7,7 @@ import ( "io" "os" + "github.com/containerd/platforms" "github.com/distribution/reference" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" @@ -17,6 +18,7 @@ import ( "github.com/moby/moby/api/pkg/authconfig" registrytypes "github.com/moby/moby/api/types/registry" "github.com/moby/moby/client" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/spf13/cobra" ) @@ -78,6 +80,13 @@ func runPull(ctx context.Context, dockerCLI command.Cli, opts pullOptions) error } } + if opts.platform != "" { + // TODO(thaJeztah): add a platform option-type / flag-type. + if _, err = platforms.Parse(opts.platform); err != nil { + return err + } + } + imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver(dockerCLI), distributionRef.String()) if err != nil { return err @@ -104,11 +113,17 @@ func imagePullPrivileged(ctx context.Context, dockerCLI command.Cli, ref referen if err != nil { return err } + var ociPlatforms []ocispec.Platform + if opts.platform != "" { + // Already validated. + ociPlatforms = append(ociPlatforms, platforms.MustParse(opts.platform)) + } + responseBody, err := dockerCLI.Client().ImagePull(ctx, reference.FamiliarString(ref), client.ImagePullOptions{ RegistryAuth: encodedAuth, PrivilegeFunc: nil, All: opts.all, - Platform: opts.platform, + Platforms: ociPlatforms, }) if err != nil { return err diff --git a/cli/command/registry/login.go b/cli/command/registry/login.go index 266a40192..17d0d883b 100644 --- a/cli/command/registry/login.go +++ b/cli/command/registry/login.go @@ -173,7 +173,7 @@ func loginWithStoredCredentials(ctx context.Context, dockerCLI command.Cli, auth } else { _, _ = fmt.Fprintln(dockerCLI.Err(), "Login did not succeed, error:", err) } - // TODO(thaJeztah): should this return the error here, or is there a reasong for continuing? + // TODO(thaJeztah): should this return the error here, or is there a reason for continuing? } if resp.Auth.IdentityToken != "" { diff --git a/cli/command/stack/client_test.go b/cli/command/stack/client_test.go index 118e7edf1..9c308c700 100644 --- a/cli/command/stack/client_test.go +++ b/cli/command/stack/client_test.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/docker/cli/cli/compose/convert" - "github.com/moby/moby/api/types" "github.com/moby/moby/api/types/network" "github.com/moby/moby/api/types/swarm" "github.com/moby/moby/client" @@ -38,9 +37,8 @@ type fakeClient struct { configRemoveFunc func(configID string) (client.ConfigRemoveResult, error) } -func (*fakeClient) ServerVersion(context.Context) (types.Version, error) { - return types.Version{ - Version: "docker-dev", +func (*fakeClient) ServerVersion(context.Context, client.ServerVersionOptions) (client.ServerVersionResult, error) { + return client.ServerVersionResult{ APIVersion: client.MaxAPIVersion, }, nil } diff --git a/cli/command/system/client_test.go b/cli/command/system/client_test.go index b2099d332..de58b9191 100644 --- a/cli/command/system/client_test.go +++ b/cli/command/system/client_test.go @@ -3,7 +3,6 @@ package system import ( "context" - "github.com/moby/moby/api/types" "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/events" "github.com/moby/moby/client" @@ -21,7 +20,7 @@ type fakeClient struct { networkListFunc func(ctx context.Context, options client.NetworkListOptions) (client.NetworkListResult, error) networkPruneFunc func(ctx context.Context, options client.NetworkPruneOptions) (client.NetworkPruneResult, error) nodeListFunc func(ctx context.Context, options client.NodeListOptions) (client.NodeListResult, error) - serverVersion func(ctx context.Context) (types.Version, error) + serverVersion func(ctx context.Context, options client.ServerVersionOptions) (client.ServerVersionResult, error) volumeListFunc func(ctx context.Context, options client.VolumeListOptions) (client.VolumeListResult, error) } @@ -89,8 +88,8 @@ func (cli *fakeClient) NodeList(ctx context.Context, options client.NodeListOpti return client.NodeListResult{}, nil } -func (cli *fakeClient) ServerVersion(ctx context.Context) (types.Version, error) { - return cli.serverVersion(ctx) +func (cli *fakeClient) ServerVersion(ctx context.Context, options client.ServerVersionOptions) (client.ServerVersionResult, error) { + return cli.serverVersion(ctx, options) } func (cli *fakeClient) VolumeList(ctx context.Context, options client.VolumeListOptions) (client.VolumeListResult, error) { diff --git a/cli/command/system/testdata/TestVersionFormat/json.golden b/cli/command/system/testdata/TestVersionFormat/json.golden index 088d7dc46..3d3de4a37 100644 --- a/cli/command/system/testdata/TestVersionFormat/json.golden +++ b/cli/command/system/testdata/TestVersionFormat/json.golden @@ -1 +1 @@ -{"Client":{"Version":"18.99.5-ce","ApiVersion":"1.38","DefaultAPIVersion":"1.38","GitCommit":"deadbeef","GoVersion":"go1.10.2","Os":"linux","Arch":"amd64","BuildTime":"Wed May 30 22:21:05 2018","Context":"my-context"},"Server":{"Platform":{"Name":"Docker Enterprise Edition (EE) 2.0"},"Components":[{"Name":"Engine","Version":"17.06.2-ee-15","Details":{"ApiVersion":"1.30","Arch":"amd64","BuildTime":"Mon Jul 9 23:38:38 2018","Experimental":"false","GitCommit":"64ddfa6","GoVersion":"go1.8.7","MinAPIVersion":"1.12","Os":"linux"}},{"Name":"Universal Control Plane","Version":"17.06.2-ee-15","Details":{"ApiVersion":"1.30","Arch":"amd64","BuildTime":"Mon Jul 2 21:24:07 UTC 2018","GitCommit":"4513922","GoVersion":"go1.9.4","MinApiVersion":"1.20","Os":"linux","Version":"3.0.3-tp2"}},{"Name":"Kubernetes","Version":"1.8+","Details":{"buildDate":"2018-04-26T16:51:21Z","compiler":"gc","gitCommit":"8d637aedf46b9c21dde723e29c645b9f27106fa5","gitTreeState":"clean","gitVersion":"v1.8.11-docker-8d637ae","goVersion":"go1.8.3","major":"1","minor":"8+","platform":"linux/amd64"}},{"Name":"Calico","Version":"v3.0.8","Details":{"cni":"v2.0.6","kube-controllers":"v2.0.5","node":"v3.0.8"}}],"Version":"","ApiVersion":"","GitCommit":"","GoVersion":"","Os":"","Arch":""}} +{"Client":{"Version":"18.99.5-ce","ApiVersion":"1.38","DefaultAPIVersion":"1.38","GitCommit":"deadbeef","GoVersion":"go1.10.2","Os":"linux","Arch":"amd64","BuildTime":"Wed May 30 22:21:05 2018","Context":"my-context"},"Server":{"Platform":{"Name":"Docker Enterprise Edition (EE) 2.0"},"Version":"","APIVersion":"","MinAPIVersion":"","Os":"","Arch":"","Experimental":false,"Components":[{"Name":"Engine","Version":"17.06.2-ee-15","Details":{"ApiVersion":"1.30","Arch":"amd64","BuildTime":"Mon Jul 9 23:38:38 2018","Experimental":"false","GitCommit":"64ddfa6","GoVersion":"go1.8.7","MinAPIVersion":"1.12","Os":"linux"}},{"Name":"Universal Control Plane","Version":"17.06.2-ee-15","Details":{"ApiVersion":"1.30","Arch":"amd64","BuildTime":"Mon Jul 2 21:24:07 UTC 2018","GitCommit":"4513922","GoVersion":"go1.9.4","MinApiVersion":"1.20","Os":"linux","Version":"3.0.3-tp2"}},{"Name":"Kubernetes","Version":"1.8+","Details":{"buildDate":"2018-04-26T16:51:21Z","compiler":"gc","gitCommit":"8d637aedf46b9c21dde723e29c645b9f27106fa5","gitTreeState":"clean","gitVersion":"v1.8.11-docker-8d637ae","goVersion":"go1.8.3","major":"1","minor":"8+","platform":"linux/amd64"}},{"Name":"Calico","Version":"v3.0.8","Details":{"cni":"v2.0.6","kube-controllers":"v2.0.5","node":"v3.0.8"}}]}} diff --git a/cli/command/system/testdata/TestVersionFormat/json_template.golden b/cli/command/system/testdata/TestVersionFormat/json_template.golden index 088d7dc46..3d3de4a37 100644 --- a/cli/command/system/testdata/TestVersionFormat/json_template.golden +++ b/cli/command/system/testdata/TestVersionFormat/json_template.golden @@ -1 +1 @@ -{"Client":{"Version":"18.99.5-ce","ApiVersion":"1.38","DefaultAPIVersion":"1.38","GitCommit":"deadbeef","GoVersion":"go1.10.2","Os":"linux","Arch":"amd64","BuildTime":"Wed May 30 22:21:05 2018","Context":"my-context"},"Server":{"Platform":{"Name":"Docker Enterprise Edition (EE) 2.0"},"Components":[{"Name":"Engine","Version":"17.06.2-ee-15","Details":{"ApiVersion":"1.30","Arch":"amd64","BuildTime":"Mon Jul 9 23:38:38 2018","Experimental":"false","GitCommit":"64ddfa6","GoVersion":"go1.8.7","MinAPIVersion":"1.12","Os":"linux"}},{"Name":"Universal Control Plane","Version":"17.06.2-ee-15","Details":{"ApiVersion":"1.30","Arch":"amd64","BuildTime":"Mon Jul 2 21:24:07 UTC 2018","GitCommit":"4513922","GoVersion":"go1.9.4","MinApiVersion":"1.20","Os":"linux","Version":"3.0.3-tp2"}},{"Name":"Kubernetes","Version":"1.8+","Details":{"buildDate":"2018-04-26T16:51:21Z","compiler":"gc","gitCommit":"8d637aedf46b9c21dde723e29c645b9f27106fa5","gitTreeState":"clean","gitVersion":"v1.8.11-docker-8d637ae","goVersion":"go1.8.3","major":"1","minor":"8+","platform":"linux/amd64"}},{"Name":"Calico","Version":"v3.0.8","Details":{"cni":"v2.0.6","kube-controllers":"v2.0.5","node":"v3.0.8"}}],"Version":"","ApiVersion":"","GitCommit":"","GoVersion":"","Os":"","Arch":""}} +{"Client":{"Version":"18.99.5-ce","ApiVersion":"1.38","DefaultAPIVersion":"1.38","GitCommit":"deadbeef","GoVersion":"go1.10.2","Os":"linux","Arch":"amd64","BuildTime":"Wed May 30 22:21:05 2018","Context":"my-context"},"Server":{"Platform":{"Name":"Docker Enterprise Edition (EE) 2.0"},"Version":"","APIVersion":"","MinAPIVersion":"","Os":"","Arch":"","Experimental":false,"Components":[{"Name":"Engine","Version":"17.06.2-ee-15","Details":{"ApiVersion":"1.30","Arch":"amd64","BuildTime":"Mon Jul 9 23:38:38 2018","Experimental":"false","GitCommit":"64ddfa6","GoVersion":"go1.8.7","MinAPIVersion":"1.12","Os":"linux"}},{"Name":"Universal Control Plane","Version":"17.06.2-ee-15","Details":{"ApiVersion":"1.30","Arch":"amd64","BuildTime":"Mon Jul 2 21:24:07 UTC 2018","GitCommit":"4513922","GoVersion":"go1.9.4","MinApiVersion":"1.20","Os":"linux","Version":"3.0.3-tp2"}},{"Name":"Kubernetes","Version":"1.8+","Details":{"buildDate":"2018-04-26T16:51:21Z","compiler":"gc","gitCommit":"8d637aedf46b9c21dde723e29c645b9f27106fa5","gitTreeState":"clean","gitVersion":"v1.8.11-docker-8d637ae","goVersion":"go1.8.3","major":"1","minor":"8+","platform":"linux/amd64"}},{"Name":"Calico","Version":"v3.0.8","Details":{"cni":"v2.0.6","kube-controllers":"v2.0.5","node":"v3.0.8"}}]}} diff --git a/cli/command/system/version.go b/cli/command/system/version.go index 5f5937c59..6d89885bf 100644 --- a/cli/command/system/version.go +++ b/cli/command/system/version.go @@ -6,7 +6,6 @@ import ( "io" "runtime" "sort" - "strconv" "text/template" "time" @@ -17,7 +16,7 @@ import ( flagsHelper "github.com/docker/cli/cli/flags" "github.com/docker/cli/cli/version" "github.com/docker/cli/templates" - "github.com/moby/moby/api/types" + "github.com/moby/moby/api/types/system" "github.com/moby/moby/client" "github.com/spf13/cobra" "github.com/tonistiigi/go-rosetta" @@ -64,7 +63,7 @@ type versionOptions struct { // versionInfo contains version information of both the Client, and Server type versionInfo struct { Client clientVersion - Server *types.Version + Server *client.ServerVersionResult } type platformInfo struct { @@ -153,12 +152,10 @@ func runVersion(ctx context.Context, dockerCli command.Cli, opts *versionOptions return cli.StatusError{StatusCode: 64, Status: err.Error()} } - // TODO print error if kubernetes is used? - vd := versionInfo{ Client: newClientVersion(dockerCli.CurrentContext(), dockerCli), } - sv, err := dockerCli.Client().ServerVersion(ctx) + sv, err := dockerCli.Client().ServerVersion(ctx, client.ServerVersionOptions{}) if err == nil { vd.Server = &sv foundEngine := false @@ -173,18 +170,14 @@ func runVersion(ctx context.Context, dockerCli command.Cli, opts *versionOptions } if !foundEngine { - vd.Server.Components = append(vd.Server.Components, types.ComponentVersion{ + vd.Server.Components = append(vd.Server.Components, system.ComponentVersion{ Name: "Engine", Version: sv.Version, Details: map[string]string{ "ApiVersion": sv.APIVersion, "MinAPIVersion": sv.MinAPIVersion, - "GitCommit": sv.GitCommit, - "GoVersion": sv.GoVersion, "Os": sv.Os, "Arch": sv.Arch, - "BuildTime": reformatDate(vd.Server.BuildTime), - "Experimental": strconv.FormatBool(sv.Experimental), }, }) } @@ -217,7 +210,7 @@ func newVersionTemplate(templateFormat string) (*template.Template, error) { return tmpl, nil } -func getDetailsOrder(v types.ComponentVersion) []string { +func getDetailsOrder(v system.ComponentVersion) []string { out := make([]string, 0, len(v.Details)) for k := range v.Details { out = append(out, k) diff --git a/cli/command/system/version_test.go b/cli/command/system/version_test.go index 4bd2c217a..eeb60cc29 100644 --- a/cli/command/system/version_test.go +++ b/cli/command/system/version_test.go @@ -9,7 +9,8 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/moby/moby/api/types" + "github.com/moby/moby/api/types/system" + "github.com/moby/moby/client" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" "gotest.tools/v3/golden" @@ -17,8 +18,8 @@ import ( func TestVersionWithoutServer(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ - serverVersion: func(ctx context.Context) (types.Version, error) { - return types.Version{}, errors.New("no server") + serverVersion: func(ctx context.Context, options client.ServerVersionOptions) (client.ServerVersionResult, error) { + return client.ServerVersionResult{}, errors.New("no server") }, }) cmd := newVersionCommand(cli) @@ -46,9 +47,9 @@ func TestVersionFormat(t *testing.T) { BuildTime: "Wed May 30 22:21:05 2018", Context: "my-context", }, - Server: &types.Version{ - Platform: struct{ Name string }{Name: "Docker Enterprise Edition (EE) 2.0"}, - Components: []types.ComponentVersion{ + Server: &client.ServerVersionResult{ + Platform: client.PlatformInfo{Name: "Docker Enterprise Edition (EE) 2.0"}, + Components: []system.ComponentVersion{ { Name: "Engine", Version: "17.06.2-ee-15", diff --git a/internal/jsonstream/display.go b/internal/jsonstream/display.go index 6ba27aaa2..de9d1e2cb 100644 --- a/internal/jsonstream/display.go +++ b/internal/jsonstream/display.go @@ -11,8 +11,8 @@ import ( type ( JSONError = jsonstream.Error - JSONMessage = jsonmessage.JSONMessage - JSONProgress = jsonmessage.JSONProgress + JSONMessage = jsonstream.Message + JSONProgress = jsonstream.Progress ) type ctxReader struct { diff --git a/internal/jsonstream/display_test.go b/internal/jsonstream/display_test.go index 2acfc3a54..05bed621e 100644 --- a/internal/jsonstream/display_test.go +++ b/internal/jsonstream/display_test.go @@ -33,12 +33,10 @@ func TestDisplay(t *testing.T) { err := enc.Encode(JSONMessage{ Status: "Downloading", ID: fmt.Sprintf("id-%d", i), - Progress: &JSONProgress{ - Progress: jsonstream.Progress{ - Current: int64(i), - Total: 100, - Start: 0, - }, + Progress: &jsonstream.Progress{ + Current: int64(i), + Total: 100, + Start: 0, }, }) if err != nil { diff --git a/vendor.mod b/vendor.mod index 72916c7ef..7c2f750ca 100644 --- a/vendor.mod +++ b/vendor.mod @@ -28,8 +28,8 @@ require ( github.com/google/uuid v1.6.0 github.com/mattn/go-runewidth v0.0.17 github.com/moby/go-archive v0.1.0 - github.com/moby/moby/api v1.52.0-beta.2.0.20251029225139-7a97e1cb401f // master - github.com/moby/moby/client v0.1.0-beta.2.0.20251029225139-7a97e1cb401f // master + github.com/moby/moby/api v1.52.0-beta.3.0.20251031021517-d96f50518f8d // master + github.com/moby/moby/client v0.1.0-beta.2.0.20251031021517-d96f50518f8d // master github.com/moby/patternmatcher v0.6.0 github.com/moby/swarmkit/v2 v2.1.0 github.com/moby/sys/atomicwriter v0.1.0 diff --git a/vendor.sum b/vendor.sum index b4e9327af..07408782a 100644 --- a/vendor.sum +++ b/vendor.sum @@ -170,10 +170,10 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= -github.com/moby/moby/api v1.52.0-beta.2.0.20251029225139-7a97e1cb401f h1:agkZxo7k3fXBqdq6leYCCv0K45OjkH/H3fzPjwcoDkY= -github.com/moby/moby/api v1.52.0-beta.2.0.20251029225139-7a97e1cb401f/go.mod h1:v0K/motq8oWmx+rtApG1rBTIpQ8KUONUjpf+U73gags= -github.com/moby/moby/client v0.1.0-beta.2.0.20251029225139-7a97e1cb401f h1:I0uikdmKsCbOxQV+DIn7gyY8bD0d19g8920FuxI9l3E= -github.com/moby/moby/client v0.1.0-beta.2.0.20251029225139-7a97e1cb401f/go.mod h1:1YrJTvhL771Q4xiwwe72NSS17lgsCF67xu8fEfSd77g= +github.com/moby/moby/api v1.52.0-beta.3.0.20251031021517-d96f50518f8d h1:yv97052L6n+B7nwsJSms4aC8qDJcFKEuAoyNQAjJcUg= +github.com/moby/moby/api v1.52.0-beta.3.0.20251031021517-d96f50518f8d/go.mod h1:v0K/motq8oWmx+rtApG1rBTIpQ8KUONUjpf+U73gags= +github.com/moby/moby/client v0.1.0-beta.2.0.20251031021517-d96f50518f8d h1:wXNr/8nLcBwLH9RujUs3KgAxmGkpQ0AvQlTAnVaigoA= +github.com/moby/moby/client v0.1.0-beta.2.0.20251031021517-d96f50518f8d/go.mod h1:1YrJTvhL771Q4xiwwe72NSS17lgsCF67xu8fEfSd77g= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/swarmkit/v2 v2.1.0 h1:u+cJ5hSyF3HnzsyI+NtegYxdIPQIuibk7IbpXNxuISM= diff --git a/vendor/github.com/moby/moby/api/types/network/endpoint.go b/vendor/github.com/moby/moby/api/types/network/endpoint.go index ee98fab01..cd39c579f 100644 --- a/vendor/github.com/moby/moby/api/types/network/endpoint.go +++ b/vendor/github.com/moby/moby/api/types/network/endpoint.go @@ -30,7 +30,7 @@ type EndpointSettings struct { // MacAddress may be used to specify a MAC address when the container is created. // Once the container is running, it becomes operational data (it may contain a // generated address). - MacAddress string + MacAddress HardwareAddr IPPrefixLen int IPv6Gateway netip.Addr GlobalIPv6Address netip.Addr diff --git a/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go b/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go index 6ff25b1bb..bf493ad5d 100644 --- a/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go +++ b/vendor/github.com/moby/moby/api/types/network/endpoint_resource.go @@ -24,7 +24,7 @@ type EndpointResource struct { // mac address // Example: 02:42:ac:13:00:02 - MacAddress string `json:"MacAddress"` + MacAddress HardwareAddr `json:"MacAddress"` // IPv4 address // Example: 172.19.0.2/16 diff --git a/vendor/github.com/moby/moby/api/types/network/hwaddr.go b/vendor/github.com/moby/moby/api/types/network/hwaddr.go new file mode 100644 index 000000000..9d0c2b4b6 --- /dev/null +++ b/vendor/github.com/moby/moby/api/types/network/hwaddr.go @@ -0,0 +1,37 @@ +package network + +import ( + "encoding" + "fmt" + "net" +) + +// A HardwareAddr represents a physical hardware address. +// It implements [encoding.TextMarshaler] and [encoding.TextUnmarshaler] +// in the absence of go.dev/issue/29678. +type HardwareAddr net.HardwareAddr + +var _ encoding.TextMarshaler = (HardwareAddr)(nil) +var _ encoding.TextUnmarshaler = (*HardwareAddr)(nil) +var _ fmt.Stringer = (HardwareAddr)(nil) + +func (m *HardwareAddr) UnmarshalText(text []byte) error { + if len(text) == 0 { + *m = nil + return nil + } + hw, err := net.ParseMAC(string(text)) + if err != nil { + return err + } + *m = HardwareAddr(hw) + return nil +} + +func (m HardwareAddr) MarshalText() ([]byte, error) { + return []byte(net.HardwareAddr(m).String()), nil +} + +func (m HardwareAddr) String() string { + return net.HardwareAddr(m).String() +} diff --git a/vendor/github.com/moby/moby/api/types/system/version_response.go b/vendor/github.com/moby/moby/api/types/system/version_response.go new file mode 100644 index 000000000..61cd1b6e2 --- /dev/null +++ b/vendor/github.com/moby/moby/api/types/system/version_response.go @@ -0,0 +1,58 @@ +package system + +// VersionResponse contains information about the Docker server host. +// GET "/version" +type VersionResponse struct { + // Platform is the platform (product name) the server is running on. + Platform PlatformInfo `json:",omitempty"` + + // Version is the version of the daemon. + Version string + + // APIVersion is the highest API version supported by the server. + APIVersion string `json:"ApiVersion"` + + // MinAPIVersion is the minimum API version the server supports. + MinAPIVersion string `json:"MinAPIVersion,omitempty"` + + // Os is the operating system the server runs on. + Os string + + // Arch is the hardware architecture the server runs on. + Arch string + + // Components contains version information for the components making + // up the server. Information in this field is for informational + // purposes, and not part of the API contract. + Components []ComponentVersion `json:",omitempty"` + + // The following fields are deprecated, they relate to the Engine component and are kept for backwards compatibility + + GitCommit string `json:",omitempty"` + GoVersion string `json:",omitempty"` + KernelVersion string `json:",omitempty"` + Experimental bool `json:",omitempty"` + BuildTime string `json:",omitempty"` +} + +// PlatformInfo holds information about the platform (product name) the +// server is running on. +type PlatformInfo struct { + // Name is the name of the platform (for example, "Docker Engine - Community", + // or "Docker Desktop 4.49.0 (208003)") + Name string +} + +// ComponentVersion describes the version information for a specific component. +type ComponentVersion struct { + Name string + Version string + + // Details contains Key/value pairs of strings with additional information + // about the component. These values are intended for informational purposes + // only, and their content is not defined, and not part of the API + // specification. + // + // These messages can be printed by the client as information to the user. + Details map[string]string `json:",omitempty"` +} diff --git a/vendor/github.com/moby/moby/api/types/types.go b/vendor/github.com/moby/moby/api/types/types.go index 8457ca041..a89befdda 100644 --- a/vendor/github.com/moby/moby/api/types/types.go +++ b/vendor/github.com/moby/moby/api/types/types.go @@ -16,39 +16,3 @@ const ( // MediaTypeJSONSequence is the MIME-Type for JSON Text Sequences (RFC7464). MediaTypeJSONSequence = "application/json-seq" ) - -// ComponentVersion describes the version information for a specific component. -type ComponentVersion struct { - Name string - Version string - Details map[string]string `json:",omitempty"` -} - -// Version contains response of Engine API: -// GET "/version" -type Version struct { - Platform struct{ Name string } `json:",omitempty"` - Components []ComponentVersion `json:",omitempty"` - - // The following fields are deprecated, they relate to the Engine component and are kept for backwards compatibility - - Version string - APIVersion string `json:"ApiVersion"` - MinAPIVersion string `json:"MinAPIVersion,omitempty"` - GitCommit string - GoVersion string - Os string - Arch string - KernelVersion string `json:",omitempty"` - Experimental bool `json:",omitempty"` - BuildTime string `json:",omitempty"` -} - -// PushResult contains the tag, manifest digest, and manifest size from the -// push. It's used to signal this information to the trust code in the client -// so it can sign the manifest if necessary. -type PushResult struct { - Tag string - Digest string - Size int -} diff --git a/vendor/github.com/moby/moby/client/README.md b/vendor/github.com/moby/moby/client/README.md index 35a8a0692..c8c5b96f9 100644 --- a/vendor/github.com/moby/moby/client/README.md +++ b/vendor/github.com/moby/moby/client/README.md @@ -23,7 +23,7 @@ import ( ) func main() { - apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { panic(err) } diff --git a/vendor/github.com/moby/moby/client/client.go b/vendor/github.com/moby/moby/client/client.go index 8fe97d590..3d1186144 100644 --- a/vendor/github.com/moby/moby/client/client.go +++ b/vendor/github.com/moby/moby/client/client.go @@ -6,7 +6,7 @@ https://docs.docker.com/reference/api/engine/ # Usage -You use the library by constructing a client object using [NewClientWithOpts] +You use the library by constructing a client object using [New] and calling methods on it. The client can be configured from environment variables by passing the [FromEnv] option, and the [WithAPIVersionNegotiation] option to allow downgrading the API version used when connecting with an older @@ -30,7 +30,7 @@ For example, to list running containers (the equivalent of "docker ps"): // for configuration (DOCKER_HOST, DOCKER_API_VERSION), and does // API-version negotiation to allow downgrading the API version // when connecting with an older daemon version. - apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + apiClient, err := client.New(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { log.Fatal(err) } @@ -160,7 +160,14 @@ func CheckRedirect(_ *http.Request, via []*http.Request) error { return ErrRedirect } -// NewClientWithOpts initializes a new API client with a default HTTPClient, and +// NewClientWithOpts initializes a new API client. +// +// Deprecated: use New. This function will be removed in the next release. +func NewClientWithOpts(ops ...Opt) (*Client, error) { + return New(ops...) +} + +// New initializes a new API client with a default HTTPClient, and // default API host and version. It also initializes the custom HTTP headers to // add to each request. // @@ -170,11 +177,11 @@ func CheckRedirect(_ *http.Request, via []*http.Request) error { // itself with values from environment variables ([FromEnv]), and has automatic // API version negotiation enabled ([WithAPIVersionNegotiation]). // -// cli, err := client.NewClientWithOpts( +// cli, err := client.New( // client.FromEnv, // client.WithAPIVersionNegotiation(), // ) -func NewClientWithOpts(ops ...Opt) (*Client, error) { +func New(ops ...Opt) (*Client, error) { hostURL, err := ParseHostURL(DefaultDockerHost) if err != nil { return nil, err diff --git a/vendor/github.com/moby/moby/client/client_interfaces.go b/vendor/github.com/moby/moby/client/client_interfaces.go index 9e7d4c164..b599b595b 100644 --- a/vendor/github.com/moby/moby/client/client_interfaces.go +++ b/vendor/github.com/moby/moby/client/client_interfaces.go @@ -5,7 +5,6 @@ import ( "io" "net" - "github.com/moby/moby/api/types" "github.com/moby/moby/api/types/network" "github.com/moby/moby/api/types/system" ) @@ -27,7 +26,7 @@ type stableAPIClient interface { VolumeAPIClient ClientVersion() string DaemonHost() string - ServerVersion(ctx context.Context) (types.Version, error) + ServerVersion(ctx context.Context, options ServerVersionOptions) (ServerVersionResult, error) HijackDialer Dialer() func(context.Context) (net.Conn, error) Close() error diff --git a/vendor/github.com/moby/moby/client/image_build.go b/vendor/github.com/moby/moby/client/image_build.go index 67c7e160a..5062ec5de 100644 --- a/vendor/github.com/moby/moby/client/image_build.go +++ b/vendor/github.com/moby/moby/client/image_build.go @@ -8,8 +8,8 @@ import ( "net/http" "net/url" "strconv" - "strings" + cerrdefs "github.com/containerd/errdefs" "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/network" ) @@ -154,8 +154,12 @@ func (cli *Client) imageBuildOptionsToQuery(_ context.Context, options ImageBuil if options.SessionID != "" { query.Set("session", options.SessionID) } - if options.Platform != "" { - query.Set("platform", strings.ToLower(options.Platform)) + if len(options.Platforms) > 0 { + if len(options.Platforms) > 1 { + // TODO(thaJeztah): update API spec and add equivalent check on the daemon. We need this still for older daemons, which would ignore it. + return query, cerrdefs.ErrInvalidArgument.WithMessage("specifying multiple platforms is not yet supported") + } + query.Set("platform", formatPlatform(options.Platforms[0])) } if options.BuildID != "" { query.Set("buildid", options.BuildID) diff --git a/vendor/github.com/moby/moby/client/image_build_opts.go b/vendor/github.com/moby/moby/client/image_build_opts.go index effb259e3..f65ad0f2b 100644 --- a/vendor/github.com/moby/moby/client/image_build_opts.go +++ b/vendor/github.com/moby/moby/client/image_build_opts.go @@ -6,6 +6,7 @@ import ( "github.com/moby/moby/api/types/build" "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/registry" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // ImageBuildOptions holds the information @@ -50,7 +51,9 @@ type ImageBuildOptions struct { ExtraHosts []string // List of extra hosts Target string SessionID string - Platform string + // Platforms selects the platforms to build the image for. Multiple platforms + // can be provided if the daemon supports multi-platform builds. + Platforms []ocispec.Platform // Version specifies the version of the underlying builder to use Version build.BuilderVersion // BuildID is an optional identifier that can be passed together with the diff --git a/vendor/github.com/moby/moby/client/image_create.go b/vendor/github.com/moby/moby/client/image_create.go index 25e8a57ec..4d429570c 100644 --- a/vendor/github.com/moby/moby/client/image_create.go +++ b/vendor/github.com/moby/moby/client/image_create.go @@ -4,8 +4,8 @@ import ( "context" "net/http" "net/url" - "strings" + cerrdefs "github.com/containerd/errdefs" "github.com/distribution/reference" "github.com/moby/moby/api/types/registry" ) @@ -21,8 +21,12 @@ func (cli *Client) ImageCreate(ctx context.Context, parentReference string, opti query := url.Values{} query.Set("fromImage", ref.Name()) query.Set("tag", getAPITagFromNamedRef(ref)) - if options.Platform != "" { - query.Set("platform", strings.ToLower(options.Platform)) + if len(options.Platforms) > 0 { + if len(options.Platforms) > 1 { + // TODO(thaJeztah): update API spec and add equivalent check on the daemon. We need this still for older daemons, which would ignore it. + return ImageCreateResult{}, cerrdefs.ErrInvalidArgument.WithMessage("specifying multiple platforms is not yet supported") + } + query.Set("platform", formatPlatform(options.Platforms[0])) } resp, err := cli.tryImageCreate(ctx, query, staticAuth(options.RegistryAuth)) if err != nil { diff --git a/vendor/github.com/moby/moby/client/image_create_opts.go b/vendor/github.com/moby/moby/client/image_create_opts.go index 301cf0bb8..eb4c486c7 100644 --- a/vendor/github.com/moby/moby/client/image_create_opts.go +++ b/vendor/github.com/moby/moby/client/image_create_opts.go @@ -1,11 +1,18 @@ package client -import "io" +import ( + "io" + + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) // ImageCreateOptions holds information to create images. type ImageCreateOptions struct { RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry. - Platform string // Platform is the target platform of the image if it needs to be pulled from the registry. + // Platforms specifies the platforms to platform of the image if it needs + // to be pulled from the registry. Multiple platforms can be provided + // if the daemon supports multi-platform pulls. + Platforms []ocispec.Platform } // ImageCreateResult holds the response body returned by the daemon for image create. diff --git a/vendor/github.com/moby/moby/client/image_import.go b/vendor/github.com/moby/moby/client/image_import.go index b8f1ccb50..3718ab50c 100644 --- a/vendor/github.com/moby/moby/client/image_import.go +++ b/vendor/github.com/moby/moby/client/image_import.go @@ -3,7 +3,6 @@ package client import ( "context" "net/url" - "strings" "github.com/distribution/reference" ) @@ -31,8 +30,9 @@ func (cli *Client) ImageImport(ctx context.Context, source ImageImportSource, re if options.Message != "" { query.Set("message", options.Message) } - if options.Platform != "" { - query.Set("platform", strings.ToLower(options.Platform)) + if p := formatPlatform(options.Platform); p != "unknown" { + // TODO(thaJeztah): would we ever support mutiple platforms here? (would require multiple rootfs tars as well?) + query.Set("platform", p) } for _, change := range options.Changes { query.Add("changes", change) diff --git a/vendor/github.com/moby/moby/client/image_import_opts.go b/vendor/github.com/moby/moby/client/image_import_opts.go index 2ba5b593e..513548cc3 100644 --- a/vendor/github.com/moby/moby/client/image_import_opts.go +++ b/vendor/github.com/moby/moby/client/image_import_opts.go @@ -2,6 +2,8 @@ package client import ( "io" + + ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // ImageImportSource holds source information for ImageImport @@ -12,10 +14,10 @@ type ImageImportSource struct { // ImageImportOptions holds information to import images from the client host. type ImageImportOptions struct { - Tag string // Tag is the name to tag this image with. This attribute is deprecated. - Message string // Message is the message to tag the image with - Changes []string // Changes are the raw changes to apply to this image - Platform string // Platform is the target platform of the image + Tag string // Tag is the name to tag this image with. This attribute is deprecated. + Message string // Message is the message to tag the image with + Changes []string // Changes are the raw changes to apply to this image + Platform ocispec.Platform // Platform is the target platform of the image } // ImageImportResult holds the response body returned by the daemon for image import. diff --git a/vendor/github.com/moby/moby/client/image_pull.go b/vendor/github.com/moby/moby/client/image_pull.go index f111adc10..e6e576a79 100644 --- a/vendor/github.com/moby/moby/client/image_pull.go +++ b/vendor/github.com/moby/moby/client/image_pull.go @@ -5,17 +5,16 @@ import ( "io" "iter" "net/url" - "strings" cerrdefs "github.com/containerd/errdefs" "github.com/distribution/reference" + "github.com/moby/moby/api/types/jsonstream" "github.com/moby/moby/client/internal" - "github.com/moby/moby/client/pkg/jsonmessage" ) type ImagePullResponse interface { io.ReadCloser - JSONMessages(ctx context.Context) iter.Seq2[jsonmessage.JSONMessage, error] + JSONMessages(ctx context.Context) iter.Seq2[jsonstream.Message, error] Wait(ctx context.Context) error } @@ -44,10 +43,13 @@ func (cli *Client) ImagePull(ctx context.Context, refStr string, options ImagePu if !options.All { query.Set("tag", getAPITagFromNamedRef(ref)) } - if options.Platform != "" { - query.Set("platform", strings.ToLower(options.Platform)) + if len(options.Platforms) > 0 { + if len(options.Platforms) > 1 { + // TODO(thaJeztah): update API spec and add equivalent check on the daemon. We need this still for older daemons, which would ignore it. + return nil, cerrdefs.ErrInvalidArgument.WithMessage("specifying multiple platforms is not yet supported") + } + query.Set("platform", formatPlatform(options.Platforms[0])) } - resp, err := cli.tryImageCreate(ctx, query, staticAuth(options.RegistryAuth)) if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { resp, err = cli.tryImageCreate(ctx, query, options.PrivilegeFunc) diff --git a/vendor/github.com/moby/moby/client/image_pull_opts.go b/vendor/github.com/moby/moby/client/image_pull_opts.go index 3f1042a88..1b78185dd 100644 --- a/vendor/github.com/moby/moby/client/image_pull_opts.go +++ b/vendor/github.com/moby/moby/client/image_pull_opts.go @@ -2,6 +2,8 @@ package client import ( "context" + + ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // ImagePullOptions holds information to pull images. @@ -16,5 +18,8 @@ type ImagePullOptions struct { // // For details, refer to [github.com/moby/moby/api/types/registry.RequestAuthConfig]. PrivilegeFunc func(context.Context) (string, error) - Platform string + + // Platforms selects the platforms to pull. Multiple platforms can be + // specified if the image ia a multi-platform image. + Platforms []ocispec.Platform } diff --git a/vendor/github.com/moby/moby/client/image_push.go b/vendor/github.com/moby/moby/client/image_push.go index 66114d615..5dd8bc140 100644 --- a/vendor/github.com/moby/moby/client/image_push.go +++ b/vendor/github.com/moby/moby/client/image_push.go @@ -12,14 +12,14 @@ import ( cerrdefs "github.com/containerd/errdefs" "github.com/distribution/reference" + "github.com/moby/moby/api/types/jsonstream" "github.com/moby/moby/api/types/registry" "github.com/moby/moby/client/internal" - "github.com/moby/moby/client/pkg/jsonmessage" ) type ImagePushResponse interface { io.ReadCloser - JSONMessages(ctx context.Context) iter.Seq2[jsonmessage.JSONMessage, error] + JSONMessages(ctx context.Context) iter.Seq2[jsonstream.Message, error] Wait(ctx context.Context) error } diff --git a/vendor/github.com/moby/moby/client/internal/jsonmessages.go b/vendor/github.com/moby/moby/client/internal/jsonmessages.go index 275de21eb..ebbb5faa3 100644 --- a/vendor/github.com/moby/moby/client/internal/jsonmessages.go +++ b/vendor/github.com/moby/moby/client/internal/jsonmessages.go @@ -8,7 +8,7 @@ import ( "iter" "sync" - "github.com/moby/moby/client/pkg/jsonmessage" + "github.com/moby/moby/api/types/jsonstream" ) func NewJSONMessageStream(rc io.ReadCloser) stream { @@ -44,15 +44,15 @@ func (r stream) Close() error { // JSONMessages decodes the response stream as a sequence of JSONMessages. // if stream ends or context is cancelled, the underlying [io.Reader] is closed. -func (r stream) JSONMessages(ctx context.Context) iter.Seq2[jsonmessage.JSONMessage, error] { +func (r stream) JSONMessages(ctx context.Context) iter.Seq2[jsonstream.Message, error] { context.AfterFunc(ctx, func() { _ = r.Close() }) dec := json.NewDecoder(r) - return func(yield func(jsonmessage.JSONMessage, error) bool) { + return func(yield func(jsonstream.Message, error) bool) { defer r.Close() for { - var jm jsonmessage.JSONMessage + var jm jsonstream.Message err := dec.Decode(&jm) if errors.Is(err, io.EOF) { break diff --git a/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go b/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go index 1c661e970..9e949c5e2 100644 --- a/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go +++ b/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go @@ -14,28 +14,14 @@ import ( "github.com/moby/term" ) +var timeNow = time.Now // For overriding in tests. + // RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to // ensure the formatted time isalways the same number of characters. const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00" -// JSONProgress describes a progress message in a JSON stream. -type JSONProgress struct { - jsonstream.Progress - - // terminalFd is the fd of the current terminal, if any. It is used - // to get the terminal width. - terminalFd uintptr - - // nowFunc is used to override the current time in tests. - nowFunc func() time.Time - - // winSize is used to override the terminal width in tests. - winSize int -} - -func (p *JSONProgress) String() string { +func RenderTUIProgress(p jsonstream.Progress, width uint16) string { var ( - width = p.width() pbBox string numbersBox string ) @@ -89,7 +75,7 @@ func (p *JSONProgress) String() string { var timeLeftBox string if width > 50 { if p.Current > 0 && p.Start > 0 && percentage < 50 { - fromStart := p.now().Sub(time.Unix(p.Start, 0)) + fromStart := timeNow().UTC().Sub(time.Unix(p.Start, 0)) perEntry := fromStart / time.Duration(p.Current) left := time.Duration(p.Total-p.Current) * perEntry timeLeftBox = " " + left.Round(time.Second).String() @@ -98,40 +84,6 @@ func (p *JSONProgress) String() string { return pbBox + numbersBox + timeLeftBox } -// now returns the current time in UTC, but can be overridden in tests -// by setting JSONProgress.nowFunc to a custom function. -func (p *JSONProgress) now() time.Time { - if p.nowFunc != nil { - return p.nowFunc() - } - return time.Now().UTC() -} - -// width returns the current terminal's width, but can be overridden -// in tests by setting JSONProgress.winSize to a non-zero value. -func (p *JSONProgress) width() int { - if p.winSize != 0 { - return p.winSize - } - ws, err := term.GetWinsize(p.terminalFd) - if err == nil { - return int(ws.Width) - } - return 200 -} - -// JSONMessage defines a message struct. It describes -// the created time, where it from, status, ID of the -// message. It's used for docker events. -type JSONMessage struct { - Stream string `json:"stream,omitempty"` - Status string `json:"status,omitempty"` - Progress *JSONProgress `json:"progressDetail,omitempty"` - ID string `json:"id,omitempty"` - Error *jsonstream.Error `json:"errorDetail,omitempty"` - Aux *json.RawMessage `json:"aux,omitempty"` // Aux contains out-of-band data, such as digests for push signing and image id after building. -} - // We can probably use [aec.EmptyBuilder] for managing the output, but // currently we're doing it all manually, so defining some consts for // the basics we use. @@ -164,7 +116,7 @@ func cursorDown(out io.Writer, l uint) { // Display prints the JSONMessage to out. If isTerminal is true, it erases // the entire current line when displaying the progressbar. It returns an // error if the [JSONMessage.Error] field is non-nil. -func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error { +func Display(jm jsonstream.Message, out io.Writer, isTerminal bool, width uint16) error { if jm.Error != nil { return jm.Error } @@ -173,14 +125,17 @@ func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error { clearLine(out) endl = "\r" _, _ = fmt.Fprint(out, endl) - } else if jm.Progress != nil && jm.Progress.String() != "" { // disable progressbar in non-terminal + } else if jm.Progress != nil && (jm.Progress.Current > 0 || jm.Progress.Total > 0) { // disable progressbar in non-terminal return nil } if jm.ID != "" { _, _ = fmt.Fprintf(out, "%s: ", jm.ID) } if jm.Progress != nil && isTerminal { - _, _ = fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl) + if width == 0 { + width = 200 + } + _, _ = fmt.Fprintf(out, "%s %s%s", jm.Status, RenderTUIProgress(*jm.Progress, width), endl) } else if jm.Stream != "" { _, _ = fmt.Fprintf(out, "%s%s", jm.Stream, endl) } else { @@ -189,16 +144,16 @@ func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error { return nil } -type JSONMessagesStream iter.Seq2[JSONMessage, error] +type JSONMessagesStream iter.Seq2[jsonstream.Message, error] // DisplayJSONMessagesStream reads a JSON message stream from in, and writes // each [JSONMessage] to out. // see DisplayJSONMessages for details -func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(JSONMessage)) error { +func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(jsonstream.Message)) error { dec := json.NewDecoder(in) - var f JSONMessagesStream = func(yield func(JSONMessage, error) bool) { + var f JSONMessagesStream = func(yield func(jsonstream.Message, error) bool) { for { - var jm JSONMessage + var jm jsonstream.Message err := dec.Decode(&jm) if errors.Is(err, io.EOF) { break @@ -228,8 +183,15 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, // - auxCallback allows handling the [JSONMessage.Aux] field. It is // called if a JSONMessage contains an Aux field, in which case // DisplayJSONMessagesStream does not present the JSONMessage. -func DisplayJSONMessages(messages JSONMessagesStream, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(JSONMessage)) error { +func DisplayJSONMessages(messages JSONMessagesStream, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(jsonstream.Message)) error { ids := make(map[string]uint) + var width uint16 = 200 + if isTerminal { + ws, err := term.GetWinsize(terminalFd) + if err == nil { + width = ws.Width + } + } for jm, err := range messages { var diff uint @@ -244,9 +206,6 @@ func DisplayJSONMessages(messages JSONMessagesStream, out io.Writer, terminalFd continue } - if jm.Progress != nil { - jm.Progress.terminalFd = terminalFd - } if jm.ID != "" && jm.Progress != nil { line, ok := ids[jm.ID] if !ok { @@ -274,7 +233,7 @@ func DisplayJSONMessages(messages JSONMessagesStream, out io.Writer, terminalFd // with multiple tags). ids = make(map[string]uint) } - err := jm.Display(out, isTerminal) + err := Display(jm, out, isTerminal, width) if jm.ID != "" && isTerminal { cursorDown(out, diff) } diff --git a/vendor/github.com/moby/moby/client/version.go b/vendor/github.com/moby/moby/client/version.go index 46c70b8ad..7fa5a3fa0 100644 --- a/vendor/github.com/moby/moby/client/version.go +++ b/vendor/github.com/moby/moby/client/version.go @@ -4,18 +4,78 @@ import ( "context" "encoding/json" - "github.com/moby/moby/api/types" + "github.com/moby/moby/api/types/system" ) -// ServerVersion returns information of the docker client and server host. -func (cli *Client) ServerVersion(ctx context.Context) (types.Version, error) { +// ServerVersionOptions specifies options for the server version request. +type ServerVersionOptions struct { + // Currently no options are supported. +} + +// ServerVersionResult contains information about the Docker server host. +type ServerVersionResult struct { + // Platform is the platform (product name) the server is running on. + Platform PlatformInfo + + // Version is the version of the daemon. + Version string + + // APIVersion is the highest API version supported by the server. + APIVersion string + + // MinAPIVersion is the minimum API version the server supports. + MinAPIVersion string + + // Os is the operating system the server runs on. + Os string + + // Arch is the hardware architecture the server runs on. + Arch string + + // Experimental indicates that the daemon runs with experimental + // features enabled. + // + // Deprecated: this field will be removed in the next version. + Experimental bool + + // Components contains version information for the components making + // up the server. Information in this field is for informational + // purposes, and not part of the API contract. + Components []system.ComponentVersion +} + +// PlatformInfo holds information about the platform (product name) the +// server is running on. +type PlatformInfo struct { + // Name is the name of the platform (for example, "Docker Engine - Community", + // or "Docker Desktop 4.49.0 (208003)") + Name string +} + +// ServerVersion returns information of the Docker server host. +func (cli *Client) ServerVersion(ctx context.Context, _ ServerVersionOptions) (ServerVersionResult, error) { resp, err := cli.get(ctx, "/version", nil, nil) defer ensureReaderClosed(resp) if err != nil { - return types.Version{}, err + return ServerVersionResult{}, err } - var server types.Version - err = json.NewDecoder(resp.Body).Decode(&server) - return server, err + var v system.VersionResponse + err = json.NewDecoder(resp.Body).Decode(&v) + if err != nil { + return ServerVersionResult{}, err + } + + return ServerVersionResult{ + Platform: PlatformInfo{ + Name: v.Platform.Name, + }, + Version: v.Version, + APIVersion: v.APIVersion, + MinAPIVersion: v.MinAPIVersion, + Os: v.Os, + Arch: v.Arch, + Experimental: v.Experimental, //nolint:staticcheck // ignore deprecated field. + Components: v.Components, + }, nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index 68335c66b..de6e6dbca 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -168,7 +168,7 @@ github.com/moby/docker-image-spec/specs-go/v1 github.com/moby/go-archive github.com/moby/go-archive/compression github.com/moby/go-archive/tarheader -# github.com/moby/moby/api v1.52.0-beta.2.0.20251029225139-7a97e1cb401f +# github.com/moby/moby/api v1.52.0-beta.3.0.20251031021517-d96f50518f8d ## explicit; go 1.23.0 github.com/moby/moby/api/pkg/authconfig github.com/moby/moby/api/pkg/stdcopy @@ -190,7 +190,7 @@ github.com/moby/moby/api/types/storage github.com/moby/moby/api/types/swarm github.com/moby/moby/api/types/system github.com/moby/moby/api/types/volume -# github.com/moby/moby/client v0.1.0-beta.2.0.20251029225139-7a97e1cb401f +# github.com/moby/moby/client v0.1.0-beta.2.0.20251031021517-d96f50518f8d ## explicit; go 1.23.0 github.com/moby/moby/client github.com/moby/moby/client/internal