diff --git a/cli/command/container/hijack.go b/cli/command/container/hijack.go index 192e35773..2a2705204 100644 --- a/cli/command/container/hijack.go +++ b/cli/command/container/hijack.go @@ -8,7 +8,7 @@ import ( "sync" "github.com/docker/cli/cli/command" - "github.com/moby/moby/api/stdcopy" + "github.com/moby/moby/api/pkg/stdcopy" "github.com/moby/moby/client" "github.com/moby/term" "github.com/sirupsen/logrus" diff --git a/cli/command/container/logs.go b/cli/command/container/logs.go index e33276f0a..63e6898cc 100644 --- a/cli/command/container/logs.go +++ b/cli/command/container/logs.go @@ -7,7 +7,7 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" - "github.com/moby/moby/api/stdcopy" + "github.com/moby/moby/api/pkg/stdcopy" "github.com/moby/moby/api/types/container" "github.com/spf13/cobra" ) diff --git a/cli/command/container/opts.go b/cli/command/container/opts.go index af1ffeede..e5ae857d9 100644 --- a/cli/command/container/opts.go +++ b/cli/command/container/opts.go @@ -414,8 +414,8 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con publishOpts := copts.publish.GetSlice() var ( - ports map[nat.Port]struct{} - portBindings map[nat.Port][]nat.PortBinding + ports map[container.PortRangeProto]struct{} + portBindings map[container.PortRangeProto][]container.PortBinding convertedOpts []string ) diff --git a/cli/command/container/opts_test.go b/cli/command/container/opts_test.go index 06ae8a33b..395d6e39a 100644 --- a/cli/command/container/opts_test.go +++ b/cli/command/container/opts_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - "github.com/docker/go-connections/nat" "github.com/moby/moby/api/types/container" networktypes "github.com/moby/moby/api/types/network" "github.com/spf13/pflag" @@ -439,7 +438,7 @@ func TestParseWithExpose(t *testing.T) { "8080-NaN/tcp": `invalid range format for --expose: 8080-NaN/tcp, error: strconv.ParseUint: parsing "NaN": invalid syntax`, "1234567890-8080/tcp": `invalid range format for --expose: 1234567890-8080/tcp, error: strconv.ParseUint: parsing "1234567890": value out of range`, } - valids := map[string][]nat.Port{ + valids := map[string][]container.PortRangeProto{ "8080/tcp": {"8080/tcp"}, "8080/udp": {"8080/udp"}, "8080/ncp": {"8080/ncp"}, @@ -473,7 +472,7 @@ func TestParseWithExpose(t *testing.T) { if len(config.ExposedPorts) != 2 { t.Fatalf("Expected 2 exposed ports, got %v", config.ExposedPorts) } - ports := []nat.Port{"80/tcp", "81/tcp"} + ports := []container.PortRangeProto{"80/tcp", "81/tcp"} for _, port := range ports { if _, ok := config.ExposedPorts[port]; !ok { t.Fatalf("Expected %v, got %v", ports, config.ExposedPorts) diff --git a/cli/command/container/port.go b/cli/command/container/port.go index 3ed950f37..1e93b7442 100644 --- a/cli/command/container/port.go +++ b/cli/command/container/port.go @@ -11,8 +11,8 @@ import ( "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command/completion" - "github.com/docker/go-connections/nat" "github.com/fvbommel/sortorder" + "github.com/moby/moby/api/types/container" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -67,7 +67,7 @@ func runPort(ctx context.Context, dockerCli command.Cli, opts *portOptions) erro if _, err = strconv.ParseUint(port, 10, 16); err != nil { return errors.Wrapf(err, "Error: invalid port (%s)", port) } - frontends, exists := c.NetworkSettings.Ports[nat.Port(port+"/"+proto)] + frontends, exists := c.NetworkSettings.Ports[container.PortRangeProto(port+"/"+proto)] if !exists || len(frontends) == 0 { return errors.Errorf("Error: No public port '%s' published for %s", opts.port, opts.container) } diff --git a/cli/command/container/port_test.go b/cli/command/container/port_test.go index 86706543e..009c78385 100644 --- a/cli/command/container/port_test.go +++ b/cli/command/container/port_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/docker/cli/internal/test" - "github.com/docker/go-connections/nat" "github.com/moby/moby/api/types/container" "gotest.tools/v3/assert" "gotest.tools/v3/golden" @@ -47,19 +46,19 @@ func TestNewPortCommandOutput(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ inspectFunc: func(string) (container.InspectResponse, error) { ci := container.InspectResponse{NetworkSettings: &container.NetworkSettings{}} - ci.NetworkSettings.Ports = nat.PortMap{ - "80/tcp": make([]nat.PortBinding, len(tc.ips)), - "443/tcp": make([]nat.PortBinding, len(tc.ips)), - "443/udp": make([]nat.PortBinding, len(tc.ips)), + ci.NetworkSettings.Ports = container.PortMap{ + "80/tcp": make([]container.PortBinding, len(tc.ips)), + "443/tcp": make([]container.PortBinding, len(tc.ips)), + "443/udp": make([]container.PortBinding, len(tc.ips)), } for i, ip := range tc.ips { - ci.NetworkSettings.Ports["80/tcp"][i] = nat.PortBinding{ + ci.NetworkSettings.Ports["80/tcp"][i] = container.PortBinding{ HostIP: ip, HostPort: "3456", } - ci.NetworkSettings.Ports["443/tcp"][i] = nat.PortBinding{ + ci.NetworkSettings.Ports["443/tcp"][i] = container.PortBinding{ HostIP: ip, HostPort: "4567", } - ci.NetworkSettings.Ports["443/udp"][i] = nat.PortBinding{ + ci.NetworkSettings.Ports["443/udp"][i] = container.PortBinding{ HostIP: ip, HostPort: "5678", } } diff --git a/cli/command/container/run_test.go b/cli/command/container/run_test.go index ceccefd22..5f7e617e2 100644 --- a/cli/command/container/run_test.go +++ b/cli/command/container/run_test.go @@ -16,12 +16,13 @@ import ( "github.com/docker/cli/cli/streams" "github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test/notary" - "github.com/docker/docker/pkg/jsonmessage" "github.com/moby/moby/api/types" "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/image" + "github.com/moby/moby/api/types/jsonstream" "github.com/moby/moby/api/types/network" "github.com/moby/moby/client" + "github.com/moby/moby/client/pkg/jsonmessage" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/spf13/pflag" "gotest.tools/v3/assert" @@ -256,9 +257,11 @@ func TestRunPullTermination(t *testing.T) { TimeNano: time.Now().UnixNano(), Time: time.Now().Unix(), Progress: &jsonmessage.JSONProgress{ - Current: int64(i), - Total: 100, - Start: 0, + Progress: jsonstream.Progress{ + Current: int64(i), + Total: 100, + Start: 0, + }, }, })) time.Sleep(100 * time.Millisecond) diff --git a/cli/command/image/build.go b/cli/command/image/build.go index b356f66f0..2bbb0b755 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -20,9 +20,9 @@ import ( "github.com/docker/cli/cli/streams" "github.com/docker/cli/internal/jsonstream" "github.com/docker/cli/opts" - "github.com/docker/docker/pkg/progress" - "github.com/docker/docker/pkg/streamformatter" "github.com/moby/go-archive" + "github.com/moby/moby/api/pkg/progress" + "github.com/moby/moby/api/pkg/streamformatter" buildtypes "github.com/moby/moby/api/types/build" "github.com/moby/moby/api/types/container" registrytypes "github.com/moby/moby/api/types/registry" diff --git a/cli/command/image/build/context.go b/cli/command/image/build/context.go index add175c2c..2f514018a 100644 --- a/cli/command/image/build/context.go +++ b/cli/command/image/build/context.go @@ -17,10 +17,10 @@ import ( "time" "github.com/docker/cli/cli/command/image/build/internal/git" - "github.com/docker/docker/pkg/progress" - "github.com/docker/docker/pkg/streamformatter" "github.com/moby/go-archive" "github.com/moby/go-archive/compression" + "github.com/moby/moby/api/pkg/progress" + "github.com/moby/moby/api/pkg/streamformatter" "github.com/moby/patternmatcher" "github.com/pkg/errors" ) diff --git a/cli/command/service/logs.go b/cli/command/service/logs.go index 940178427..99e7c3697 100644 --- a/cli/command/service/logs.go +++ b/cli/command/service/logs.go @@ -16,7 +16,7 @@ import ( "github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/idresolver" "github.com/docker/cli/internal/logdetails" - "github.com/moby/moby/api/stdcopy" + "github.com/moby/moby/api/pkg/stdcopy" "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/swarm" "github.com/moby/moby/client" diff --git a/cli/command/service/progress/progress.go b/cli/command/service/progress/progress.go index 2caa26889..95e8e9453 100644 --- a/cli/command/service/progress/progress.go +++ b/cli/command/service/progress/progress.go @@ -12,8 +12,8 @@ import ( "time" "github.com/docker/cli/cli/command/formatter" - "github.com/docker/docker/pkg/progress" - "github.com/docker/docker/pkg/streamformatter" + "github.com/moby/moby/api/pkg/progress" + "github.com/moby/moby/api/pkg/streamformatter" "github.com/moby/moby/api/types/filters" "github.com/moby/moby/api/types/swarm" "github.com/moby/moby/client" diff --git a/cli/command/service/progress/progress_test.go b/cli/command/service/progress/progress_test.go index a71833e81..133596c93 100644 --- a/cli/command/service/progress/progress_test.go +++ b/cli/command/service/progress/progress_test.go @@ -5,7 +5,7 @@ import ( "strconv" "testing" - "github.com/docker/docker/pkg/progress" + "github.com/moby/moby/api/pkg/progress" "github.com/moby/moby/api/types/swarm" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" diff --git a/cli/command/swarm/progress/root_rotation.go b/cli/command/swarm/progress/root_rotation.go index e45750c64..9cf164f31 100644 --- a/cli/command/swarm/progress/root_rotation.go +++ b/cli/command/swarm/progress/root_rotation.go @@ -8,8 +8,8 @@ import ( "os/signal" "time" - "github.com/docker/docker/pkg/progress" - "github.com/docker/docker/pkg/streamformatter" + "github.com/moby/moby/api/pkg/progress" + "github.com/moby/moby/api/pkg/streamformatter" "github.com/moby/moby/api/types/swarm" "github.com/moby/moby/client" "github.com/opencontainers/go-digest" diff --git a/cli/compose/loader/loader.go b/cli/compose/loader/loader.go index 7aa1a311e..416a475e6 100644 --- a/cli/compose/loader/loader.go +++ b/cli/compose/loader/loader.go @@ -24,6 +24,7 @@ import ( "github.com/docker/go-units" "github.com/go-viper/mapstructure/v2" "github.com/google/shlex" + "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/versions" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -934,7 +935,7 @@ func toServicePortConfigs(value string) ([]any, error) { for _, key := range keys { // Reuse ConvertPortToPortConfig so that it is consistent - portConfig, err := swarmopts.ConvertPortToPortConfig(nat.Port(key), portBindings) + portConfig, err := swarmopts.ConvertPortToPortConfig(container.PortRangeProto(key), portBindings) if err != nil { return nil, err } diff --git a/internal/jsonstream/display.go b/internal/jsonstream/display.go index 8981eca3f..6ba27aaa2 100644 --- a/internal/jsonstream/display.go +++ b/internal/jsonstream/display.go @@ -4,13 +4,14 @@ import ( "context" "io" - "github.com/docker/docker/pkg/jsonmessage" + "github.com/docker/cli/cli/streams" + "github.com/moby/moby/api/types/jsonstream" + "github.com/moby/moby/client/pkg/jsonmessage" ) type ( - Stream = jsonmessage.Stream + JSONError = jsonstream.Error JSONMessage = jsonmessage.JSONMessage - JSONError = jsonmessage.JSONError JSONProgress = jsonmessage.JSONProgress ) @@ -46,7 +47,7 @@ func WithAuxCallback(cb func(JSONMessage)) Options { // "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 { +func Display(ctx context.Context, in io.Reader, stream *streams.Out, opts ...Options) error { if ctx.Err() != nil { return ctx.Err() } diff --git a/internal/jsonstream/display_test.go b/internal/jsonstream/display_test.go index 7b14db2a9..221413721 100644 --- a/internal/jsonstream/display_test.go +++ b/internal/jsonstream/display_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/docker/cli/cli/streams" + "github.com/moby/moby/api/types/jsonstream" "gotest.tools/v3/assert" ) @@ -35,9 +36,11 @@ func TestDisplay(t *testing.T) { TimeNano: time.Now().UnixNano(), Time: time.Now().Unix(), Progress: &JSONProgress{ - Current: int64(i), - Total: 100, - Start: 0, + Progress: jsonstream.Progress{ + Current: int64(i), + Total: 100, + Start: 0, + }, }, }) if err != nil { diff --git a/opts/swarmopts/port.go b/opts/swarmopts/port.go index 12a2b60d2..6834c8d8a 100644 --- a/opts/swarmopts/port.go +++ b/opts/swarmopts/port.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/docker/go-connections/nat" + "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/swarm" "github.com/sirupsen/logrus" ) @@ -150,28 +151,31 @@ func (p *PortOpt) Value() []swarm.PortConfig { // ConvertPortToPortConfig converts ports to the swarm type func ConvertPortToPortConfig( - port nat.Port, - portBindings map[nat.Port][]nat.PortBinding, + portRangeProto container.PortRangeProto, + portBindings map[container.PortRangeProto][]container.PortBinding, ) ([]swarm.PortConfig, error) { - ports := []swarm.PortConfig{} + proto, port := nat.SplitProtoPort(string(portRangeProto)) + portInt, _ := strconv.ParseUint(port, 10, 16) + proto = strings.ToLower(proto) - for _, binding := range portBindings[port] { + var ports []swarm.PortConfig + for _, binding := range portBindings[portRangeProto] { if p := net.ParseIP(binding.HostIP); p != nil && !p.IsUnspecified() { // TODO(thaJeztah): use context-logger, so that this output can be suppressed (in tests). - logrus.Warnf("ignoring IP-address (%s:%s) service will listen on '0.0.0.0'", net.JoinHostPort(binding.HostIP, binding.HostPort), port) + logrus.Warnf("ignoring IP-address (%s:%s) service will listen on '0.0.0.0'", net.JoinHostPort(binding.HostIP, binding.HostPort), portRangeProto) } startHostPort, endHostPort, err := nat.ParsePortRange(binding.HostPort) if err != nil && binding.HostPort != "" { - return nil, fmt.Errorf("invalid hostport binding (%s) for port (%s)", binding.HostPort, port.Port()) + return nil, fmt.Errorf("invalid hostport binding (%s) for port (%s)", binding.HostPort, port) } for i := startHostPort; i <= endHostPort; i++ { ports = append(ports, swarm.PortConfig{ // TODO Name: ? - Protocol: swarm.PortConfigProtocol(strings.ToLower(port.Proto())), - TargetPort: uint32(port.Int()), + Protocol: swarm.PortConfigProtocol(proto), + TargetPort: uint32(portInt), PublishedPort: uint32(i), PublishMode: swarm.PortConfigPublishModeIngress, }) diff --git a/opts/swarmopts/port_test.go b/opts/swarmopts/port_test.go index 8b0fbc164..7a6845232 100644 --- a/opts/swarmopts/port_test.go +++ b/opts/swarmopts/port_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - "github.com/docker/go-connections/nat" + "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/swarm" "github.com/sirupsen/logrus" "gotest.tools/v3/assert" @@ -347,7 +347,7 @@ func TestConvertPortToPortConfigWithIP(t *testing.T) { logrus.SetOutput(&b) for _, tc := range testCases { t.Run(tc.value, func(t *testing.T) { - _, err := ConvertPortToPortConfig("80/tcp", map[nat.Port][]nat.PortBinding{ + _, err := ConvertPortToPortConfig("80/tcp", map[container.PortRangeProto][]container.PortBinding{ "80/tcp": {{HostIP: tc.value, HostPort: "2345"}}, }) assert.NilError(t, err) diff --git a/vendor.mod b/vendor.mod index 9692b0d55..9efdb9fcf 100644 --- a/vendor.mod +++ b/vendor.mod @@ -8,8 +8,8 @@ go 1.23.0 replace ( // FIXME(thaJeztah): temporarily need to pin on commits, otherwise go modules won't resolve until these are tagged. - github.com/moby/moby/api => github.com/moby/moby/api v0.0.0-20250729125042-2574c2b2e917 - github.com/moby/moby/client => github.com/moby/moby/client v0.0.0-20250729125042-2574c2b2e917 + github.com/moby/moby/api => github.com/moby/moby/api v0.0.0-20250731152656-4faedf2bec36 + github.com/moby/moby/client => github.com/moby/moby/client v0.0.0-20250731152656-4faedf2bec36 ) require ( @@ -22,7 +22,7 @@ require ( github.com/distribution/reference v0.6.0 github.com/docker/cli-docs-tool v0.10.0 github.com/docker/distribution v2.8.3+incompatible - github.com/docker/docker v28.2.3-0.20250729125042-2574c2b2e917+incompatible // master (v29.0-dev) + github.com/docker/docker v28.2.3-0.20250731152656-4faedf2bec36+incompatible // master (v29.0-dev) github.com/docker/docker-credential-helpers v0.9.3 github.com/docker/go-connections v0.5.0 github.com/docker/go-units v0.5.0 diff --git a/vendor.sum b/vendor.sum index 5db1160a9..5108de338 100644 --- a/vendor.sum +++ b/vendor.sum @@ -57,8 +57,8 @@ github.com/docker/cli-docs-tool v0.10.0/go.mod h1:5EM5zPnT2E7yCLERZmrDA234Vwn09f github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v28.2.3-0.20250729125042-2574c2b2e917+incompatible h1:PmHpYwC9kywp7yqeiUlJYvQaOXoYh7Xy5C1N7Z+urVo= -github.com/docker/docker v28.2.3-0.20250729125042-2574c2b2e917+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.2.3-0.20250731152656-4faedf2bec36+incompatible h1:V1yo9808DrQaHES6Q3hW5Rtd44+mrc4oKulmzPgRDAM= +github.com/docker/docker v28.2.3-0.20250731152656-4faedf2bec36+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= @@ -172,10 +172,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 v0.0.0-20250729125042-2574c2b2e917 h1:kUXvd5/UxuA9rOrBBJ79GKKuBD/HR76jJBZed/bg4+E= -github.com/moby/moby/api v0.0.0-20250729125042-2574c2b2e917/go.mod h1:UXRe3/H6L2SB5SrOqAhx5tsC0RqrhqtBoY8PFxjyp5k= -github.com/moby/moby/client v0.0.0-20250729125042-2574c2b2e917 h1:roWTPpD2XjM1Z8uYZO4HAD1pUKSpm1X5S3JqNsWYnVE= -github.com/moby/moby/client v0.0.0-20250729125042-2574c2b2e917/go.mod h1:aJbR/d6IN3wIBmj3XPFEY5E5Ndd6F57YQsqivzmCyO4= +github.com/moby/moby/api v0.0.0-20250731152656-4faedf2bec36 h1:2o6bmPZvLOYqE6mQGqnyt+556TMpa26ZtSxvgSpT+98= +github.com/moby/moby/api v0.0.0-20250731152656-4faedf2bec36/go.mod h1:GNQ0zU3WJGeJIcrLPE3xiQnsnLElvfqXQZZZiOqWuiE= +github.com/moby/moby/client v0.0.0-20250731152656-4faedf2bec36 h1:o32ntpp76dDd5Hf9+XL09+qs06120KvZl+Ogt+RkYG0= +github.com/moby/moby/client v0.0.0-20250731152656-4faedf2bec36/go.mod h1:+TFnycF6RuAUAq1tGTjZiSXuRcywpKUGo2dLkJ6tC48= 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.0.0 h1:jkWQKQaJ4ltA61/mC9UdPe1McLma55RUcacTO+pPweY= diff --git a/vendor/github.com/docker/docker/pkg/streamformatter/streamformatter.go b/vendor/github.com/docker/docker/pkg/streamformatter/streamformatter.go deleted file mode 100644 index 24e1b45f2..000000000 --- a/vendor/github.com/docker/docker/pkg/streamformatter/streamformatter.go +++ /dev/null @@ -1,164 +0,0 @@ -// Package streamformatter provides helper functions to format a stream. -package streamformatter - -import ( - "encoding/json" - "fmt" - "io" - "sync" - - "github.com/docker/docker/pkg/jsonmessage" - "github.com/docker/docker/pkg/progress" -) - -const streamNewline = "\r\n" - -type jsonProgressFormatter struct{} - -func appendNewline(source []byte) []byte { - return append(source, []byte(streamNewline)...) -} - -// FormatStatus formats the specified objects according to the specified format (and id). -func FormatStatus(id, format string, a ...interface{}) []byte { - str := fmt.Sprintf(format, a...) - b, err := json.Marshal(&jsonmessage.JSONMessage{ID: id, Status: str}) - if err != nil { - return FormatError(err) - } - return appendNewline(b) -} - -// FormatError formats the error as a JSON object -func FormatError(err error) []byte { - jsonError, ok := err.(*jsonmessage.JSONError) - if !ok { - jsonError = &jsonmessage.JSONError{Message: err.Error()} - } - if b, err := json.Marshal(&jsonmessage.JSONMessage{Error: jsonError, ErrorMessage: err.Error()}); err == nil { - return appendNewline(b) - } - return []byte(`{"error":"format error"}` + streamNewline) -} - -func (sf *jsonProgressFormatter) formatStatus(id, format string, a ...interface{}) []byte { - return FormatStatus(id, format, a...) -} - -// formatProgress formats the progress information for a specified action. -func (sf *jsonProgressFormatter) formatProgress(id, action string, progress *jsonmessage.JSONProgress, aux interface{}) []byte { - if progress == nil { - progress = &jsonmessage.JSONProgress{} - } - var auxJSON *json.RawMessage - if aux != nil { - auxJSONBytes, err := json.Marshal(aux) - if err != nil { - return nil - } - auxJSON = new(json.RawMessage) - *auxJSON = auxJSONBytes - } - b, err := json.Marshal(&jsonmessage.JSONMessage{ - Status: action, - ProgressMessage: progress.String(), - Progress: progress, - ID: id, - Aux: auxJSON, - }) - if err != nil { - return nil - } - return appendNewline(b) -} - -type rawProgressFormatter struct{} - -func (sf *rawProgressFormatter) formatStatus(id, format string, a ...interface{}) []byte { - return []byte(fmt.Sprintf(format, a...) + streamNewline) -} - -func (sf *rawProgressFormatter) formatProgress(id, action string, progress *jsonmessage.JSONProgress, aux interface{}) []byte { - if progress == nil { - progress = &jsonmessage.JSONProgress{} - } - endl := "\r" - if progress.String() == "" { - endl += "\n" - } - return []byte(action + " " + progress.String() + endl) -} - -// NewProgressOutput returns a progress.Output object that can be passed to -// progress.NewProgressReader. -func NewProgressOutput(out io.Writer) progress.Output { - return &progressOutput{sf: &rawProgressFormatter{}, out: out, newLines: true} -} - -// NewJSONProgressOutput returns a progress.Output that formats output -// using JSON objects -func NewJSONProgressOutput(out io.Writer, newLines bool) progress.Output { - return &progressOutput{sf: &jsonProgressFormatter{}, out: out, newLines: newLines} -} - -type formatProgress interface { - formatStatus(id, format string, a ...interface{}) []byte - formatProgress(id, action string, progress *jsonmessage.JSONProgress, aux interface{}) []byte -} - -type progressOutput struct { - sf formatProgress - out io.Writer - newLines bool - mu sync.Mutex -} - -// WriteProgress formats progress information from a ProgressReader. -func (out *progressOutput) WriteProgress(prog progress.Progress) error { - var formatted []byte - if prog.Message != "" { - formatted = out.sf.formatStatus(prog.ID, prog.Message) - } else { - jsonProgress := jsonmessage.JSONProgress{Current: prog.Current, Total: prog.Total, HideCounts: prog.HideCounts, Units: prog.Units} - formatted = out.sf.formatProgress(prog.ID, prog.Action, &jsonProgress, prog.Aux) - } - - out.mu.Lock() - defer out.mu.Unlock() - _, err := out.out.Write(formatted) - if err != nil { - return err - } - - if out.newLines && prog.LastUpdate { - _, err = out.out.Write(out.sf.formatStatus("", "")) - return err - } - - return nil -} - -// AuxFormatter is a streamFormatter that writes aux progress messages -type AuxFormatter struct { - io.Writer -} - -// Emit emits the given interface as an aux progress message -func (sf *AuxFormatter) Emit(id string, aux interface{}) error { - auxJSONBytes, err := json.Marshal(aux) - if err != nil { - return err - } - auxJSON := new(json.RawMessage) - *auxJSON = auxJSONBytes - msgJSON, err := json.Marshal(&jsonmessage.JSONMessage{ID: id, Aux: auxJSON}) - if err != nil { - return err - } - msgJSON = appendNewline(msgJSON) - n, err := sf.Writer.Write(msgJSON) - if n != len(msgJSON) { - return io.ErrShortWrite - } - return err -} diff --git a/vendor/github.com/docker/docker/pkg/progress/progress.go b/vendor/github.com/moby/moby/api/pkg/progress/progress.go similarity index 100% rename from vendor/github.com/docker/docker/pkg/progress/progress.go rename to vendor/github.com/moby/moby/api/pkg/progress/progress.go diff --git a/vendor/github.com/docker/docker/pkg/progress/progressreader.go b/vendor/github.com/moby/moby/api/pkg/progress/progressreader.go similarity index 100% rename from vendor/github.com/docker/docker/pkg/progress/progressreader.go rename to vendor/github.com/moby/moby/api/pkg/progress/progressreader.go diff --git a/vendor/github.com/moby/moby/api/stdcopy/stdcopy.go b/vendor/github.com/moby/moby/api/pkg/stdcopy/stdcopy.go similarity index 100% rename from vendor/github.com/moby/moby/api/stdcopy/stdcopy.go rename to vendor/github.com/moby/moby/api/pkg/stdcopy/stdcopy.go diff --git a/vendor/github.com/moby/moby/api/pkg/streamformatter/streamformatter.go b/vendor/github.com/moby/moby/api/pkg/streamformatter/streamformatter.go new file mode 100644 index 000000000..5913b568a --- /dev/null +++ b/vendor/github.com/moby/moby/api/pkg/streamformatter/streamformatter.go @@ -0,0 +1,247 @@ +// Package streamformatter provides helper functions to format a stream. +package streamformatter + +import ( + "encoding/json" + "fmt" + "io" + "strings" + "sync" + "time" + + "github.com/docker/go-units" + "github.com/moby/moby/api/pkg/progress" + "github.com/moby/moby/api/types/jsonstream" +) + +// jsonMessage defines a message struct. It describes +// the created time, where it from, status, ID of the +// message. It's used for docker events. +// +// It is a reduced set of [jsonmessage.JSONMessage]. +type jsonMessage struct { + Stream string `json:"stream,omitempty"` + Status string `json:"status,omitempty"` + Progress *jsonstream.Progress `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. + + // ErrorMessage contains errors encountered during the operation. + // + // Deprecated: this field is deprecated since docker v0.6.0 / API v1.4. Use [Error.Message] instead. This field will be omitted in a future release. + ErrorMessage string `json:"error,omitempty"` // deprecated +} + +const streamNewline = "\r\n" + +type jsonProgressFormatter struct{} + +func appendNewline(source []byte) []byte { + return append(source, []byte(streamNewline)...) +} + +// FormatStatus formats the specified objects according to the specified format (and id). +func FormatStatus(id, format string, a ...interface{}) []byte { + str := fmt.Sprintf(format, a...) + b, err := json.Marshal(&jsonMessage{ID: id, Status: str}) + if err != nil { + return FormatError(err) + } + return appendNewline(b) +} + +// FormatError formats the error as a JSON object +func FormatError(err error) []byte { + jsonError, ok := err.(*jsonstream.Error) + if !ok { + jsonError = &jsonstream.Error{Message: err.Error()} + } + if b, err := json.Marshal(&jsonMessage{Error: jsonError, ErrorMessage: err.Error()}); err == nil { + return appendNewline(b) + } + return []byte(`{"error":"format error"}` + streamNewline) +} + +func (sf *jsonProgressFormatter) formatStatus(id, format string, a ...interface{}) []byte { + return FormatStatus(id, format, a...) +} + +// formatProgress formats the progress information for a specified action. +func (sf *jsonProgressFormatter) formatProgress(id, action string, progress *jsonstream.Progress, aux interface{}) []byte { + if progress == nil { + progress = &jsonstream.Progress{} + } + var auxJSON *json.RawMessage + if aux != nil { + auxJSONBytes, err := json.Marshal(aux) + if err != nil { + return nil + } + auxJSON = new(json.RawMessage) + *auxJSON = auxJSONBytes + } + b, err := json.Marshal(&jsonMessage{ + Status: action, + Progress: progress, + ID: id, + Aux: auxJSON, + }) + if err != nil { + return nil + } + return appendNewline(b) +} + +type rawProgressFormatter struct{} + +func (sf *rawProgressFormatter) formatStatus(id, format string, a ...interface{}) []byte { + return []byte(fmt.Sprintf(format, a...) + streamNewline) +} + +func rawProgressString(p *jsonstream.Progress) string { + if p == nil || (p.Current <= 0 && p.Total <= 0) { + return "" + } + if p.Total <= 0 { + switch p.Units { + case "": + return fmt.Sprintf("%8v", units.HumanSize(float64(p.Current))) + default: + return fmt.Sprintf("%d %s", p.Current, p.Units) + } + } + + percentage := int(float64(p.Current)/float64(p.Total)*100) / 2 + if percentage > 50 { + percentage = 50 + } + + numSpaces := 0 + if 50-percentage > 0 { + numSpaces = 50 - percentage + } + pbBox := fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces)) + + var numbersBox string + switch { + case p.HideCounts: + case p.Units == "": // no units, use bytes + current := units.HumanSize(float64(p.Current)) + total := units.HumanSize(float64(p.Total)) + + numbersBox = fmt.Sprintf("%8v/%v", current, total) + + if p.Current > p.Total { + // remove total display if the reported current is wonky. + numbersBox = fmt.Sprintf("%8v", current) + } + default: + numbersBox = fmt.Sprintf("%d/%d %s", p.Current, p.Total, p.Units) + + if p.Current > p.Total { + // remove total display if the reported current is wonky. + numbersBox = fmt.Sprintf("%d %s", p.Current, p.Units) + } + } + + var timeLeftBox string + if p.Current > 0 && p.Start > 0 && percentage < 50 { + fromStart := time.Since(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() + } + return pbBox + numbersBox + timeLeftBox +} + +func (sf *rawProgressFormatter) formatProgress(id, action string, progress *jsonstream.Progress, aux interface{}) []byte { + if progress == nil { + progress = &jsonstream.Progress{} + } + endl := "\r" + out := rawProgressString(progress) + if out == "" { + endl += "\n" + } + return []byte(action + " " + out + endl) +} + +// NewProgressOutput returns a progress.Output object that can be passed to +// progress.NewProgressReader. +func NewProgressOutput(out io.Writer) progress.Output { + return &progressOutput{sf: &rawProgressFormatter{}, out: out, newLines: true} +} + +// NewJSONProgressOutput returns a progress.Output that formats output +// using JSON objects +func NewJSONProgressOutput(out io.Writer, newLines bool) progress.Output { + return &progressOutput{sf: &jsonProgressFormatter{}, out: out, newLines: newLines} +} + +type formatProgress interface { + formatStatus(id, format string, a ...interface{}) []byte + formatProgress(id, action string, progress *jsonstream.Progress, aux interface{}) []byte +} + +type progressOutput struct { + sf formatProgress + out io.Writer + newLines bool + mu sync.Mutex +} + +// WriteProgress formats progress information from a ProgressReader. +func (out *progressOutput) WriteProgress(prog progress.Progress) error { + var formatted []byte + if prog.Message != "" { + formatted = out.sf.formatStatus(prog.ID, prog.Message) + } else { + jsonProgress := jsonstream.Progress{ + Current: prog.Current, + Total: prog.Total, + HideCounts: prog.HideCounts, + Units: prog.Units, + } + formatted = out.sf.formatProgress(prog.ID, prog.Action, &jsonProgress, prog.Aux) + } + + out.mu.Lock() + defer out.mu.Unlock() + _, err := out.out.Write(formatted) + if err != nil { + return err + } + + if out.newLines && prog.LastUpdate { + _, err = out.out.Write(out.sf.formatStatus("", "")) + return err + } + + return nil +} + +// AuxFormatter is a streamFormatter that writes aux progress messages +type AuxFormatter struct { + io.Writer +} + +// Emit emits the given interface as an aux progress message +func (sf *AuxFormatter) Emit(id string, aux interface{}) error { + auxJSONBytes, err := json.Marshal(aux) + if err != nil { + return err + } + auxJSON := new(json.RawMessage) + *auxJSON = auxJSONBytes + msgJSON, err := json.Marshal(&jsonMessage{ID: id, Aux: auxJSON}) + if err != nil { + return err + } + msgJSON = appendNewline(msgJSON) + n, err := sf.Writer.Write(msgJSON) + if n != len(msgJSON) { + return io.ErrShortWrite + } + return err +} diff --git a/vendor/github.com/docker/docker/pkg/streamformatter/streamwriter.go b/vendor/github.com/moby/moby/api/pkg/streamformatter/streamwriter.go similarity index 90% rename from vendor/github.com/docker/docker/pkg/streamformatter/streamwriter.go rename to vendor/github.com/moby/moby/api/pkg/streamformatter/streamwriter.go index 141d12e20..a5f26d565 100644 --- a/vendor/github.com/docker/docker/pkg/streamformatter/streamwriter.go +++ b/vendor/github.com/moby/moby/api/pkg/streamformatter/streamwriter.go @@ -3,8 +3,6 @@ package streamformatter import ( "encoding/json" "io" - - "github.com/docker/docker/pkg/jsonmessage" ) type streamWriter struct { @@ -22,7 +20,7 @@ func (sw *streamWriter) Write(buf []byte) (int, error) { } func (sw *streamWriter) format(buf []byte) []byte { - msg := &jsonmessage.JSONMessage{Stream: sw.lineFormat(buf)} + msg := &jsonMessage{Stream: sw.lineFormat(buf)} b, err := json.Marshal(msg) if err != nil { return FormatError(err) diff --git a/vendor/github.com/moby/moby/api/types/container/config.go b/vendor/github.com/moby/moby/api/types/container/config.go index 0eba9f684..6ea9e079d 100644 --- a/vendor/github.com/moby/moby/api/types/container/config.go +++ b/vendor/github.com/moby/moby/api/types/container/config.go @@ -3,7 +3,6 @@ package container import ( "time" - "github.com/docker/go-connections/nat" dockerspec "github.com/moby/docker-image-spec/specs-go/v1" "github.com/moby/moby/api/types/strslice" ) @@ -48,7 +47,7 @@ type Config struct { AttachStdin bool // Attach the standard input, makes possible user interaction AttachStdout bool // Attach the standard output AttachStderr bool // Attach the standard error - ExposedPorts nat.PortSet `json:",omitempty"` // List of exposed ports + ExposedPorts PortSet `json:",omitempty"` // List of exposed ports Tty bool // Attach standard streams to a tty, including stdin if it is not closed. OpenStdin bool // Open stdin StdinOnce bool // If true, close stdin after the 1 attached client disconnects. diff --git a/vendor/github.com/moby/moby/api/types/container/hostconfig.go b/vendor/github.com/moby/moby/api/types/container/hostconfig.go index cf27f63fc..65d430053 100644 --- a/vendor/github.com/moby/moby/api/types/container/hostconfig.go +++ b/vendor/github.com/moby/moby/api/types/container/hostconfig.go @@ -5,7 +5,6 @@ import ( "fmt" "strings" - "github.com/docker/go-connections/nat" "github.com/docker/go-units" "github.com/moby/moby/api/types/blkiodev" "github.com/moby/moby/api/types/mount" @@ -427,7 +426,7 @@ type HostConfig struct { ContainerIDFile string // File (path) where the containerId is written LogConfig LogConfig // Configuration of the logs for this container NetworkMode NetworkMode // Network mode to use for the container - PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host + PortBindings PortMap // Port mapping between the exposed port (container) and the host RestartPolicy RestartPolicy // Restart policy to be used for the container AutoRemove bool // Automatically remove container when it exits VolumeDriver string // Name of the volume driver used to mount volumes diff --git a/vendor/github.com/moby/moby/api/types/container/nat_aliases.go b/vendor/github.com/moby/moby/api/types/container/nat_aliases.go new file mode 100644 index 000000000..470f15655 --- /dev/null +++ b/vendor/github.com/moby/moby/api/types/container/nat_aliases.go @@ -0,0 +1,24 @@ +package container + +import "github.com/docker/go-connections/nat" + +// PortRangeProto is a string containing port number and protocol in the format "80/tcp", +// or a port range and protocol in the format "80-83/tcp". +// +// It is currently an alias for [nat.Port] but may become a concrete type in a future release. +type PortRangeProto = nat.Port + +// PortSet is a collection of structs indexed by [HostPort]. +// +// It is currently an alias for [nat.PortSet] but may become a concrete type in a future release. +type PortSet = nat.PortSet + +// PortBinding represents a binding between a Host IP address and a [HostPort]. +// +// It is currently an alias for [nat.PortBinding] but may become a concrete type in a future release. +type PortBinding = nat.PortBinding + +// PortMap is a collection of [PortBinding] indexed by [HostPort]. +// +// It is currently an alias for [nat.PortMap] but may become a concrete type in a future release. +type PortMap = nat.PortMap diff --git a/vendor/github.com/moby/moby/api/types/container/network_settings.go b/vendor/github.com/moby/moby/api/types/container/network_settings.go index d7dee99e7..40d5cbd1d 100644 --- a/vendor/github.com/moby/moby/api/types/container/network_settings.go +++ b/vendor/github.com/moby/moby/api/types/container/network_settings.go @@ -1,7 +1,6 @@ package container import ( - "github.com/docker/go-connections/nat" "github.com/moby/moby/api/types/network" ) @@ -14,10 +13,10 @@ type NetworkSettings struct { // NetworkSettingsBase holds networking state for a container when inspecting it. type NetworkSettingsBase struct { - Bridge string // Bridge contains the name of the default bridge interface iff it was set through the daemon --bridge flag. - SandboxID string // SandboxID uniquely represents a container's network stack - SandboxKey string // SandboxKey identifies the sandbox - Ports nat.PortMap // Ports is a collection of PortBinding indexed by Port + Bridge string // Bridge contains the name of the default bridge interface iff it was set through the daemon --bridge flag. + SandboxID string // SandboxID uniquely represents a container's network stack + SandboxKey string // SandboxKey identifies the sandbox + Ports PortMap // Ports is a collection of PortBinding indexed by Port // HairpinMode specifies if hairpin NAT should be enabled on the virtual interface // diff --git a/vendor/github.com/moby/moby/api/types/jsonstream/json_error.go b/vendor/github.com/moby/moby/api/types/jsonstream/json_error.go new file mode 100644 index 000000000..632b25fdf --- /dev/null +++ b/vendor/github.com/moby/moby/api/types/jsonstream/json_error.go @@ -0,0 +1,12 @@ +package jsonstream + +// Error wraps a concrete Code and Message, Code is +// an integer error code, Message is the error message. +type Error struct { + Code int `json:"code,omitempty"` + Message string `json:"message,omitempty"` +} + +func (e *Error) Error() string { + return e.Message +} diff --git a/vendor/github.com/moby/moby/api/types/jsonstream/progress.go b/vendor/github.com/moby/moby/api/types/jsonstream/progress.go new file mode 100644 index 000000000..5c38b3b5e --- /dev/null +++ b/vendor/github.com/moby/moby/api/types/jsonstream/progress.go @@ -0,0 +1,10 @@ +package jsonstream + +// Progress describes a progress message in a JSON stream. +type Progress struct { + Current int64 `json:"current,omitempty"` // Current is the current status and value of the progress made towards Total. + Total int64 `json:"total,omitempty"` // Total is the end value describing when we made 100% progress for an operation. + Start int64 `json:"start,omitempty"` // Start is the initial value for the operation. + HideCounts bool `json:"hidecounts,omitempty"` // HideCounts. if true, hides the progress count indicator (xB/yB). + Units string `json:"units,omitempty"` // Units is the unit to print for progress. It defaults to "bytes" if empty. +} diff --git a/vendor/github.com/moby/moby/api/types/registry/authconfig.go b/vendor/github.com/moby/moby/api/types/registry/authconfig.go index 97b9ac027..56703705a 100644 --- a/vendor/github.com/moby/moby/api/types/registry/authconfig.go +++ b/vendor/github.com/moby/moby/api/types/registry/authconfig.go @@ -52,9 +52,11 @@ type AuthConfig struct { // // [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5 func EncodeAuthConfig(authConfig AuthConfig) (string, error) { - if authConfig == (AuthConfig{}) { - return "", nil - } + // Older daemons (or registries) may not handle an empty string, + // which resulted in an "io.EOF" when unmarshaling or decoding. + // + // FIXME(thaJeztah): find exactly what code-paths are impacted by this. + // if authConfig == (AuthConfig{}) { return "", nil } buf, err := json.Marshal(authConfig) if err != nil { return "", errInvalidParameter{err} diff --git a/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go b/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go similarity index 64% rename from vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go rename to vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go index 3d072808f..bbb9581b2 100644 --- a/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go +++ b/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go @@ -8,37 +8,17 @@ import ( "time" "github.com/docker/go-units" + "github.com/moby/moby/api/types/jsonstream" "github.com/moby/term" - "github.com/morikuni/aec" ) // 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" -// JSONError wraps a concrete Code and Message, Code is -// an integer error code, Message is the error message. -type JSONError struct { - Code int `json:"code,omitempty"` - Message string `json:"message,omitempty"` -} - -func (e *JSONError) Error() string { - return e.Message -} - // JSONProgress describes a progress message in a JSON stream. type JSONProgress struct { - // Current is the current status and value of the progress made towards Total. - Current int64 `json:"current,omitempty"` - // Total is the end value describing when we made 100% progress for an operation. - Total int64 `json:"total,omitempty"` - // Start is the initial value for the operation. - Start int64 `json:"start,omitempty"` - // HideCounts. if true, hides the progress count indicator (xB/yB). - HideCounts bool `json:"hidecounts,omitempty"` - // Units is the unit to print for progress. It defaults to "bytes" if empty. - Units string `json:"units,omitempty"` + jsonstream.Progress // terminalFd is the fd of the current terminal, if any. It is used // to get the terminal width. @@ -142,40 +122,44 @@ func (p *JSONProgress) width() int { // 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"` - - // ProgressMessage is a pre-formatted presentation of [Progress]. - // - // Deprecated: this field is deprecated since docker v0.7.1 / API v1.8. Use the information in [Progress] instead. This field will be omitted in a future release. - ProgressMessage string `json:"progress,omitempty"` - ID string `json:"id,omitempty"` - From string `json:"from,omitempty"` - Time int64 `json:"time,omitempty"` - TimeNano int64 `json:"timeNano,omitempty"` - Error *JSONError `json:"errorDetail,omitempty"` - - // ErrorMessage contains errors encountered during the operation. - // - // Deprecated: this field is deprecated since docker v0.6.0 / API v1.4. Use [Error.Message] instead. This field will be omitted in a future release. - ErrorMessage string `json:"error,omitempty"` // deprecated - // Aux contains out-of-band data, such as digests for push signing and image id after building. - Aux *json.RawMessage `json:"aux,omitempty"` + Stream string `json:"stream,omitempty"` + Status string `json:"status,omitempty"` + Progress *JSONProgress `json:"progressDetail,omitempty"` + ID string `json:"id,omitempty"` + From string `json:"from,omitempty"` + Time int64 `json:"time,omitempty"` + TimeNano int64 `json:"timeNano,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. +// +// [aec.EmptyBuilder]: https://pkg.go.dev/github.com/morikuni/aec#EmptyBuilder +const ( + ansiEraseLine = "\x1b[2K" // Erase entire line + ansiCursorUpFmt = "\x1b[%dA" // Move cursor up N lines + ansiCursorDownFmt = "\x1b[%dB" // Move cursor down N lines +) + func clearLine(out io.Writer) { - eraseMode := aec.EraseModes.All - cl := aec.EraseLine(eraseMode) - fmt.Fprint(out, cl) + _, _ = out.Write([]byte(ansiEraseLine)) } func cursorUp(out io.Writer, l uint) { - fmt.Fprint(out, aec.Up(l)) + if l == 0 { + return + } + _, _ = fmt.Fprintf(out, ansiCursorUpFmt, l) } func cursorDown(out io.Writer, l uint) { - fmt.Fprint(out, aec.Down(l)) + if l == 0 { + return + } + _, _ = fmt.Fprintf(out, ansiCursorDownFmt, l) } // Display prints the JSONMessage to out. If isTerminal is true, it erases @@ -189,29 +173,27 @@ func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error { if isTerminal && jm.Stream == "" && jm.Progress != nil { clearLine(out) endl = "\r" - fmt.Fprint(out, endl) + _, _ = fmt.Fprint(out, endl) } else if jm.Progress != nil && jm.Progress.String() != "" { // disable progressbar in non-terminal return nil } if jm.TimeNano != 0 { - fmt.Fprintf(out, "%s ", time.Unix(0, jm.TimeNano).Format(RFC3339NanoFixed)) + _, _ = fmt.Fprintf(out, "%s ", time.Unix(0, jm.TimeNano).Format(RFC3339NanoFixed)) } else if jm.Time != 0 { - fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(RFC3339NanoFixed)) + _, _ = fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(RFC3339NanoFixed)) } if jm.ID != "" { - fmt.Fprintf(out, "%s: ", jm.ID) + _, _ = fmt.Fprintf(out, "%s: ", jm.ID) } if jm.From != "" { - fmt.Fprintf(out, "(from %s) ", jm.From) + _, _ = fmt.Fprintf(out, "(from %s) ", jm.From) } if jm.Progress != nil && isTerminal { - fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl) - } else if jm.ProgressMessage != "" { // deprecated - fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl) + _, _ = fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl) } else if jm.Stream != "" { - fmt.Fprintf(out, "%s%s", jm.Stream, endl) + _, _ = fmt.Fprintf(out, "%s%s", jm.Stream, endl) } else { - fmt.Fprintf(out, "%s%s\n", jm.Status, endl) + _, _ = fmt.Fprintf(out, "%s%s\n", jm.Status, endl) } return nil } @@ -258,7 +240,7 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, if jm.Progress != nil { jm.Progress.terminalFd = terminalFd } - if jm.ID != "" && (jm.Progress != nil || jm.ProgressMessage != "") { + if jm.ID != "" && jm.Progress != nil { line, ok := ids[jm.ID] if !ok { // NOTE: This approach of using len(id) to @@ -270,7 +252,7 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, line = uint(len(ids)) ids[jm.ID] = line if isTerminal { - fmt.Fprintf(out, "\n") + _, _ = fmt.Fprintf(out, "\n") } } diff = uint(len(ids)) - line @@ -295,20 +277,3 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, } return nil } - -// Stream is an io.Writer for output with utilities to get the output's file -// descriptor and to detect whether it's a terminal. -// -// it is subset of the streams.Out type in -// https://pkg.go.dev/github.com/docker/cli@v20.10.17+incompatible/cli/streams#Out -type Stream interface { - io.Writer - FD() uintptr - IsTerminal() bool -} - -// DisplayJSONMessagesToStream prints json messages to the output Stream. It is -// used by the Docker CLI to print JSONMessage streams. -func DisplayJSONMessagesToStream(in io.Reader, stream Stream, auxCallback func(JSONMessage)) error { - return DisplayJSONMessagesStream(in, stream, stream.FD(), stream.IsTerminal(), auxCallback) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 643c19972..e9095ec00 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -65,12 +65,9 @@ github.com/docker/distribution/registry/client/transport github.com/docker/distribution/registry/storage/cache github.com/docker/distribution/registry/storage/cache/memory github.com/docker/distribution/uuid -# github.com/docker/docker v28.2.3-0.20250729125042-2574c2b2e917+incompatible +# github.com/docker/docker v28.2.3-0.20250731152656-4faedf2bec36+incompatible ## explicit -github.com/docker/docker/pkg/jsonmessage github.com/docker/docker/pkg/process -github.com/docker/docker/pkg/progress -github.com/docker/docker/pkg/streamformatter # github.com/docker/docker-credential-helpers v0.9.3 ## explicit; go 1.21 github.com/docker/docker-credential-helpers/client @@ -174,9 +171,11 @@ 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 v0.0.0 => github.com/moby/moby/api v0.0.0-20250729125042-2574c2b2e917 +# github.com/moby/moby/api v0.0.0 => github.com/moby/moby/api v0.0.0-20250731152656-4faedf2bec36 ## explicit; go 1.23.0 -github.com/moby/moby/api/stdcopy +github.com/moby/moby/api/pkg/progress +github.com/moby/moby/api/pkg/stdcopy +github.com/moby/moby/api/pkg/streamformatter github.com/moby/moby/api/types github.com/moby/moby/api/types/auxprogress github.com/moby/moby/api/types/blkiodev @@ -187,6 +186,7 @@ github.com/moby/moby/api/types/container github.com/moby/moby/api/types/events github.com/moby/moby/api/types/filters github.com/moby/moby/api/types/image +github.com/moby/moby/api/types/jsonstream github.com/moby/moby/api/types/mount github.com/moby/moby/api/types/network github.com/moby/moby/api/types/registry @@ -197,9 +197,10 @@ github.com/moby/moby/api/types/system github.com/moby/moby/api/types/time github.com/moby/moby/api/types/versions github.com/moby/moby/api/types/volume -# github.com/moby/moby/client v0.0.0 => github.com/moby/moby/client v0.0.0-20250729125042-2574c2b2e917 +# github.com/moby/moby/client v0.0.0 => github.com/moby/moby/client v0.0.0-20250731152656-4faedf2bec36 ## explicit; go 1.23.0 github.com/moby/moby/client +github.com/moby/moby/client/pkg/jsonmessage github.com/moby/moby/client/pkg/stringid # github.com/moby/patternmatcher v0.6.0 ## explicit; go 1.19 @@ -571,5 +572,5 @@ gotest.tools/v3/skip # tags.cncf.io/container-device-interface v0.8.0 ## explicit; go 1.20 tags.cncf.io/container-device-interface/pkg/parser -# github.com/moby/moby/api => github.com/moby/moby/api v0.0.0-20250729125042-2574c2b2e917 -# github.com/moby/moby/client => github.com/moby/moby/client v0.0.0-20250729125042-2574c2b2e917 +# github.com/moby/moby/api => github.com/moby/moby/api v0.0.0-20250731152656-4faedf2bec36 +# github.com/moby/moby/client => github.com/moby/moby/client v0.0.0-20250731152656-4faedf2bec36