Compare commits

...

7 Commits

Author SHA1 Message Date
Sebastiaan van Stijn 8dccdd1d13
Merge be3646b87c into a93fb1678a 2024-11-21 18:31:48 +08:00
Sebastiaan van Stijn a93fb1678a
Merge pull request #5638 from thaJeztah/bump_engine
vendor: github.com/docker/docker e5c2b5e10d68 (master, v28.0.0-dev)
2024-11-21 09:54:53 +01:00
Sebastiaan van Stijn d41b80fafc
vendor: github.com/docker/docker e5c2b5e10d68 (master, v28.0.0-dev)
full diff: 6ac445c42b...e5c2b5e10d

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-11-20 15:54:27 +01:00
Sebastiaan van Stijn 81401f37f2
Merge pull request #5625 from Giedriusj1/master
Optimise `docker stats` to not require clearing the whole screen
2024-11-19 12:48:26 +01:00
Giedrius Jonikas cb2f95ceee Optimise `docker stats` to not require clearing the whole screen
Instead of clearing the whole screen and then writing the new stats,
we now write the new stats on top of the old text, and then clear
the remaining text.

This is a more efficient way to update the stats, as it avoids the
flickering that happens when the screen is cleared and rewritten.

Signed-off-by: Giedrius Jonikas <giedriusj1@gmail.com>
2024-11-16 15:29:57 +00:00
Sebastiaan van Stijn be3646b87c
image ls --tree: order images alphabetically
The tree output currently uses the same sort order as the existing
non-tree output, and orders the images by "created" time in descending
order;

    docker image ls
    REPOSITORY       TAG       IMAGE ID       CREATED          SIZE
    <none>           <none>    8262a6d8c38a   7 minutes ago    13.6MB
    docker-cli-dev   latest    f5f0547476ee   12 minutes ago   762MB
    nginx            alpine    2140dad235c1   2 weeks ago      76.7MB
    alpine           latest    beefdbd8a1da   6 weeks ago      24.2MB

However, the `--tree` view does not have a `CREATED` column, which makes
the output order seem "random". With the tree view being more verbose,
it may also be harder to find back images in the list when they're not sorted
in an easy to discover way.

This patch changes the sort order:

- alphabetically (natural sort) for tagged images
- untagged images are sorted last, as they're likely less relevant
  to the user, and should not be "polluting" th top of the list.
- if multiple untagged images exist, they are sorted by created
  date (descending) to get a stable order.

Before this patch:

    $ docker image ls --tree

    IMAGE                   ID             DISK USAGE   CONTENT SIZE   USED
    <untagged>              20ad73eca911       13.6MB         4.09MB    ✔
    └─ linux/arm64          1ab6fc68586e       13.6MB         4.09MB    ✔

    <untagged>              b3e87f642f5c       13.6MB         4.09MB
    └─ linux/arm64          1ab6fc68586e       13.6MB         4.09MB

    docker-cli-dev:latest   f5f0547476ee        762MB          179MB    ✔
    └─ linux/arm64          18ca7881145d        762MB          179MB    ✔

    nginx:alpine            2140dad235c1       76.7MB         21.5MB
    ├─ linux/arm64/v8       d1f949a77b81       76.7MB         21.5MB
    ├─ linux/amd64          ae136e431e76           0B             0B
    ├─ linux/arm/v6         ae1ee4b63c14           0B             0B
    ├─ linux/arm/v7         20ad73eca911           0B             0B
    ├─ linux/386            1e69bfb21757           0B             0B
    ├─ linux/ppc64le        7fef8bcf8b6c           0B             0B
    └─ linux/s390x          8c310bf29cfa           0B             0B

    alpine:latest           beefdbd8a1da       24.2MB         7.46MB
    ├─ linux/riscv64        80cde017a105       10.6MB         3.37MB
    ├─ linux/arm64/v8       9cee2b382fe2       13.6MB         4.09MB
    ├─ linux/amd64          33735bd63cf8           0B             0B
    ├─ linux/arm/v6         50f635c8b04d           0B             0B
    ├─ linux/arm/v7         f2f82d424957           0B             0B
    ├─ linux/386            b3e87f642f5c           0B             0B
    ├─ linux/ppc64le        c7a6800e3dc5           0B             0B
    └─ linux/s390x          2b5b26e09ca2           0B             0B

With this patch:

    $ docker image ls --tree

    IMAGE                   ID             DISK USAGE   CONTENT SIZE   USED
    alpine:latest           beefdbd8a1da       24.2MB         7.46MB
    ├─ linux/riscv64        80cde017a105       10.6MB         3.37MB
    ├─ linux/arm64/v8       9cee2b382fe2       13.6MB         4.09MB
    ├─ linux/amd64          33735bd63cf8           0B             0B
    ├─ linux/arm/v6         50f635c8b04d           0B             0B
    ├─ linux/arm/v7         f2f82d424957           0B             0B
    ├─ linux/386            b3e87f642f5c           0B             0B
    ├─ linux/ppc64le        c7a6800e3dc5           0B             0B
    └─ linux/s390x          2b5b26e09ca2           0B             0B

    docker-cli-dev:latest   f5f0547476ee        762MB          179MB    ✔
    └─ linux/arm64          18ca7881145d        762MB          179MB    ✔

    nginx:alpine            2140dad235c1       76.7MB         21.5MB
    ├─ linux/arm64/v8       d1f949a77b81       76.7MB         21.5MB
    ├─ linux/amd64          ae136e431e76           0B             0B
    ├─ linux/arm/v6         ae1ee4b63c14           0B             0B
    ├─ linux/arm/v7         20ad73eca911           0B             0B
    ├─ linux/386            1e69bfb21757           0B             0B
    ├─ linux/ppc64le        7fef8bcf8b6c           0B             0B
    └─ linux/s390x          8c310bf29cfa           0B             0B

    <untagged>              20ad73eca911       13.6MB         4.09MB    ✔
    └─ linux/arm64          1ab6fc68586e       13.6MB         4.09MB    ✔

    <untagged>              b3e87f642f5c       13.6MB         4.09MB
    └─ linux/arm64          1ab6fc68586e       13.6MB         4.09MB

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-20 23:54:57 +02:00
Sebastiaan van Stijn 7187c78554
image ls: show each tag for an image as a separate entry
A single image can be tagged under multiple names. While they are the
same image under the hood (same digest), we always presented these as
separate images in the list.

This patch applies the same behavior for the tree view; we can consider
having some "compact" presentation in future where we collapse these iamges
(perhaps introducing a "names" column?)

Before this patch:

    $ docker pull --quiet alpine:3.20
    docker.io/library/alpine:3.20
    $ docker pull --quiet alpine:latest
    docker.io/library/alpine:latest

    $ docker image ls --tree

    IMAGE                   ID             DISK USAGE   CONTENT SIZE   USED
    alpine:3.20
    alpine:latest           beefdbd8a1da       13.6MB         4.09MB
    ├─ linux/arm64/v8       9cee2b382fe2       13.6MB         4.09MB
    ├─ linux/amd64          33735bd63cf8           0B             0B
    ├─ linux/arm/v6         50f635c8b04d           0B             0B
    ├─ linux/arm/v7         f2f82d424957           0B             0B
    ├─ linux/386            b3e87f642f5c           0B             0B
    ├─ linux/ppc64le        c7a6800e3dc5           0B             0B
    ├─ linux/riscv64        80cde017a105           0B             0B
    └─ linux/s390x          2b5b26e09ca2           0B             0B

With this patch applied:

    $ docker image ls --tree

    IMAGE                   ID             DISK USAGE   CONTENT SIZE   USED
    alpine:3.20             beefdbd8a1da       13.6MB         4.09MB
    ├─ linux/arm64/v8       9cee2b382fe2       13.6MB         4.09MB
    ├─ linux/amd64          33735bd63cf8           0B             0B
    ├─ linux/arm/v6         50f635c8b04d           0B             0B
    ├─ linux/arm/v7         f2f82d424957           0B             0B
    ├─ linux/386            b3e87f642f5c           0B             0B
    ├─ linux/ppc64le        c7a6800e3dc5           0B             0B
    ├─ linux/riscv64        80cde017a105           0B             0B
    └─ linux/s390x          2b5b26e09ca2           0B             0B

    alpine:latest           beefdbd8a1da       13.6MB         4.09MB
    ├─ linux/arm64/v8       9cee2b382fe2       13.6MB         4.09MB
    ├─ linux/amd64          33735bd63cf8           0B             0B
    ├─ linux/arm/v6         50f635c8b04d           0B             0B
    ├─ linux/arm/v7         f2f82d424957           0B             0B
    ├─ linux/386            b3e87f642f5c           0B             0B
    ├─ linux/ppc64le        c7a6800e3dc5           0B             0B
    ├─ linux/riscv64        80cde017a105           0B             0B
    └─ linux/s390x          2b5b26e09ca2           0B             0B

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-10-19 19:48:45 +02:00
25 changed files with 236 additions and 79 deletions

View File

@ -287,16 +287,26 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
cStats.mu.RUnlock()
if !options.NoStream {
// Start by clearing the screen and moving the cursor to the top-left
_, _ = fmt.Fprint(&statsTextBuffer, "\033[2J\033[H")
// Start by moving the cursor to the top-left
_, _ = fmt.Fprint(&statsTextBuffer, "\033[H")
}
if err = statsFormatWrite(statsCtx, ccStats, daemonOSType, !options.NoTrunc); err != nil {
break
}
_, _ = fmt.Fprint(dockerCLI.Out(), statsTextBuffer.String())
if !options.NoStream {
for _, line := range strings.Split(statsTextBuffer.String(), "\n") {
// In case the new text is shorter than the one we are writing over,
// we'll append the "erase line" escape sequence to clear the remaining text.
_, _ = fmt.Fprint(&statsTextBuffer, line, "\033[K\n")
}
// We might have fewer containers than before, so let's clear the remaining text
_, _ = fmt.Fprint(&statsTextBuffer, "\033[J")
}
_, _ = fmt.Fprint(dockerCLI.Out(), statsTextBuffer.String())
statsTextBuffer.Reset()
if len(cStats.cs) == 0 && !showAll {

View File

@ -78,7 +78,8 @@ func runLoad(ctx context.Context, dockerCli command.Cli, opts loadOptions) error
if err != nil {
return errors.Wrap(err, "invalid platform")
}
options.Platform = &p
// TODO(thaJeztah): change flag-type to support multiple platforms.
options.Platforms = append(options.Platforms, p)
}
response, err := dockerCli.Client().ImageLoad(ctx, input, options)

View File

@ -109,7 +109,7 @@ func TestNewLoadCommandSuccess(t *testing.T) {
name: "with platform",
args: []string{"--platform", "linux/amd64"},
imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) {
assert.Check(t, is.DeepEqual(ocispec.Platform{OS: "linux", Architecture: "amd64"}, *options.Platform))
assert.Check(t, is.DeepEqual([]ocispec.Platform{{OS: "linux", Architecture: "amd64"}}, options.Platforms))
return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil
},
},

View File

@ -63,7 +63,8 @@ func RunSave(ctx context.Context, dockerCli command.Cli, opts saveOptions) error
if err != nil {
return errors.Wrap(err, "invalid platform")
}
options.Platform = &p
// TODO(thaJeztah): change flag-type to support multiple platforms.
options.Platforms = append(options.Platforms, p)
}
responseBody, err := dockerCli.Client().ImageSave(ctx, opts.images, options)

View File

@ -106,7 +106,7 @@ func TestNewSaveCommandSuccess(t *testing.T) {
imageSaveFunc: func(images []string, options image.SaveOptions) (io.ReadCloser, error) {
assert.Assert(t, is.Len(images, 1))
assert.Check(t, is.Equal("arg1", images[0]))
assert.Check(t, is.DeepEqual(ocispec.Platform{OS: "linux", Architecture: "amd64"}, *options.Platform))
assert.Check(t, is.DeepEqual([]ocispec.Platform{{OS: "linux", Architecture: "amd64"}}, options.Platforms))
return io.NopCloser(strings.NewReader("")), nil
},
},

View File

@ -14,6 +14,7 @@ import (
imagetypes "github.com/docker/docker/api/types/image"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/go-units"
"github.com/fvbommel/sortorder"
"github.com/morikuni/aec"
)
@ -81,16 +82,46 @@ func runTree(ctx context.Context, dockerCLI command.Cli, opts treeOptions) error
details.ContentSize = units.HumanSizeWithPrecision(float64(totalContent), 3)
view.images = append(view.images, topImage{
Names: img.RepoTags,
Details: details,
Children: children,
created: img.Created,
})
if len(img.RepoTags) == 0 {
// Untagged image
view.images = append(view.images, topImage{
Names: img.RepoTags,
Details: details,
Children: children,
created: img.Created,
})
} else {
// Present images tagged under multiple names as separate images.
for _, n := range img.RepoTags {
view.images = append(view.images, topImage{
Names: []string{n}, // Consider changing Names to be a single name for purpose of this presentation.
Details: details,
Children: children,
created: img.Created,
})
}
}
}
// Sort images alphabetically using natural-sort, with untagged images last.
sort.Slice(view.images, func(i, j int) bool {
return view.images[i].created > view.images[j].created
iUntagged, jUntagged := len(view.images[i].Names) == 0, len(view.images[j].Names) == 0
if iUntagged || jUntagged {
switch {
case iUntagged && jUntagged:
// Both untagged images; sort by created date (desc)
return view.images[i].created > view.images[j].created
case iUntagged:
// Sort untagged images last
return false
case jUntagged:
// Sort untagged images last
return true
}
}
// Sort alphabetically, ascending
return sortorder.NaturalLess(view.images[i].Names[0], view.images[j].Names[0])
})
return printImageTree(dockerCLI, view)

View File

@ -13,7 +13,7 @@ require (
github.com/distribution/reference v0.6.0
github.com/docker/cli-docs-tool v0.8.0
github.com/docker/distribution v2.8.3+incompatible
github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible // master (v-next)
github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible // master (v-next)
github.com/docker/docker-credential-helpers v0.8.2
github.com/docker/go-connections v0.5.0
github.com/docker/go-units v0.5.0

View File

@ -51,8 +51,8 @@ github.com/docker/cli-docs-tool v0.8.0/go.mod h1:8TQQ3E7mOXoYUs811LiPdUnAhXrcVsB
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 v27.0.2-0.20241031194140-6ac445c42bad+incompatible h1:kSQ4U+63JfFxIOrTo6wMW1mqkOkPpiTe/7ZfvUdNLVE=
github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible h1:ZWh4HhdUCagAd3S+gsFPOobHbc562obYFSrz3irGSsU=
github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=

View File

@ -1991,6 +1991,18 @@ definitions:
type: "string"
x-nullable: false
example: "sha256:ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710"
Descriptor:
description: |
Descriptor is an OCI descriptor of the image target.
In case of a multi-platform image, this descriptor points to the OCI index
or a manifest list.
This field is only present if the daemon provides a multi-platform image store.
WARNING: This is experimental and may change at any time without any backward
compatibility.
x-nullable: true
$ref: "#/definitions/OCIDescriptor"
RepoTags:
description: |
List of image names/tags in the local image cache that reference this
@ -2278,6 +2290,18 @@ definitions:
x-omitempty: true
items:
$ref: "#/definitions/ImageManifestSummary"
Descriptor:
description: |
Descriptor is an OCI descriptor of the image target.
In case of a multi-platform image, this descriptor points to the OCI index
or a manifest list.
This field is only present if the daemon provides a multi-platform image store.
WARNING: This is experimental and may change at any time without any backward
compatibility.
x-nullable: true
$ref: "#/definitions/OCIDescriptor"
AuthConfig:
type: "object"
@ -7242,6 +7266,14 @@ paths:
type: "string"
Platform:
type: "string"
ImageManifestDescriptor:
$ref: "#/definitions/OCIDescriptor"
description: |
OCI descriptor of the platform-specific manifest of the image
the container was created from.
Note: Only available if the daemon provides a multi-platform
image store.
MountLabel:
type: "string"
ProcessLabel:
@ -9210,9 +9242,14 @@ paths:
type: "string"
in: "query"
description: |
JSON encoded OCI platform describing platform to show the history for.
If not provided, the host platform will be used. If it's not
available, any present platform will be picked.
JSON-encoded OCI platform to select the platform-variant.
If omitted, it defaults to any locally available platform,
prioritizing the daemon's host platform.
If the daemon provides a multi-platform image store, this selects
the platform-variant to show the history for. If the image is
a single-platform image, or if the multi-platform image does not
provide a variant matching the given platform, an error is returned.
Example: `{"os": "linux", "architecture": "arm", "variant": "v5"}`
tags: ["Image"]
@ -9262,6 +9299,19 @@ paths:
all tags of the given image that are present in the local image store
are pushed.
type: "string"
- name: "platform"
type: "string"
in: "query"
description: |
JSON-encoded OCI platform to select the platform-variant to push.
If not provided, all available variants will attempt to be pushed.
If the daemon provides a multi-platform image store, this selects
the platform-variant to push to the registry. If the image is
a single-platform image, or if the multi-platform image does not
provide a variant matching the given platform, an error is returned.
Example: `{"os": "linux", "architecture": "arm", "variant": "v5"}`
- name: "X-Registry-Auth"
in: "header"
description: |
@ -9271,11 +9321,6 @@ paths:
details.
type: "string"
required: true
- name: "platform"
in: "query"
description: "Select a platform-specific manifest to be pushed. OCI platform (JSON encoded)"
type: "string"
x-nullable: true
tags: ["Image"]
/images/{name}/tag:
post:

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/storage"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// PruneReport contains the response for Engine API:
@ -171,4 +172,6 @@ type InspectResponse struct {
Mounts []MountPoint
Config *Config
NetworkSettings *NetworkSettings
// ImageManifestDescriptor is the descriptor of a platform-specific manifest of the image used to create the container.
ImageManifestDescriptor *ocispec.Descriptor `json:",omitempty"`
}

View File

@ -10,7 +10,7 @@ import (
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/go-connections/nat"
units "github.com/docker/go-units"
"github.com/docker/go-units"
)
// CgroupnsMode represents the cgroup namespace mode of the container

View File

@ -3,6 +3,7 @@ package image
import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/storage"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// RootFS returns Image's RootFS description including the layer IDs.
@ -119,4 +120,11 @@ type InspectResponse struct {
//
// This information is local to the daemon, and not part of the image itself.
Metadata Metadata
// Descriptor is the OCI descriptor of the image target.
// It's only set if the daemon provides a multi-platform image store.
//
// WARNING: This is experimental and may change at any time without any backward
// compatibility.
Descriptor *ocispec.Descriptor `json:"Descriptor,omitempty"`
}

View File

@ -98,12 +98,14 @@ type LoadOptions struct {
// Quiet suppresses progress output
Quiet bool
// Platform is a specific platform to load when the image is a multi-platform
Platform *ocispec.Platform
// Platforms selects the platforms to load if the image is a
// multi-platform image and has multiple variants.
Platforms []ocispec.Platform
}
// SaveOptions holds parameters to save images.
type SaveOptions struct {
// Platform is a specific platform to save if the image is a multi-platform image.
Platform *ocispec.Platform
// Platforms selects the platforms to save if the image is a
// multi-platform image and has multiple variants.
Platforms []ocispec.Platform
}

View File

@ -1,5 +1,7 @@
package image
import ocispec "github.com/opencontainers/image-spec/specs-go/v1"
type Summary struct {
// Number of containers using this image. Includes both stopped and running
@ -42,6 +44,13 @@ type Summary struct {
// Required: true
ParentID string `json:"ParentId"`
// Descriptor is the OCI descriptor of the image target.
// It's only set if the daemon provides a multi-platform image store.
//
// WARNING: This is experimental and may change at any time without any backward
// compatibility.
Descriptor *ocispec.Descriptor `json:"Descriptor,omitempty"`
// Manifests is a list of image manifests available in this image. It
// provides a more detailed view of the platform-specific image manifests or
// other image-attached data like build attestations.

View File

@ -3,7 +3,6 @@ package client // import "github.com/docker/docker/client"
import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/docker/docker/api/types/image"
@ -11,26 +10,26 @@ import (
// ImageHistory returns the changes in an image in history format.
func (cli *Client) ImageHistory(ctx context.Context, imageID string, opts image.HistoryOptions) ([]image.HistoryResponseItem, error) {
values := url.Values{}
query := url.Values{}
if opts.Platform != nil {
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
return nil, err
}
p, err := json.Marshal(*opts.Platform)
p, err := encodePlatform(opts.Platform)
if err != nil {
return nil, fmt.Errorf("invalid platform: %v", err)
return nil, err
}
values.Set("platform", string(p))
query.Set("platform", p)
}
serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", query, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return nil, err
}
var history []image.HistoryResponseItem
serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", values, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return history, err
}
err = json.NewDecoder(serverResp.body).Decode(&history)
return history, err
}

View File

@ -21,10 +21,18 @@ func (cli *Client) ImageImport(ctx context.Context, source image.ImportSource, r
}
query := url.Values{}
query.Set("fromSrc", source.SourceName)
query.Set("repo", ref)
query.Set("tag", options.Tag)
query.Set("message", options.Message)
if source.SourceName != "" {
query.Set("fromSrc", source.SourceName)
}
if ref != "" {
query.Set("repo", ref)
}
if options.Tag != "" {
query.Set("tag", options.Tag)
}
if options.Message != "" {
query.Set("message", options.Message)
}
if options.Platform != "" {
query.Set("platform", strings.ToLower(options.Platform))
}

View File

@ -2,7 +2,6 @@ package client // import "github.com/docker/docker/client"
import (
"context"
"encoding/json"
"io"
"net/http"
"net/url"
@ -18,24 +17,24 @@ import (
// the provided multi-platform image. This is only has effect if the input image
// is a multi-platform image.
func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, opts image.LoadOptions) (image.LoadResponse, error) {
v := url.Values{}
v.Set("quiet", "0")
query := url.Values{}
query.Set("quiet", "0")
if opts.Quiet {
v.Set("quiet", "1")
query.Set("quiet", "1")
}
if opts.Platform != nil {
if len(opts.Platforms) > 0 {
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
return image.LoadResponse{}, err
}
p, err := json.Marshal(*opts.Platform)
p, err := encodePlatforms(opts.Platforms...)
if err != nil {
return image.LoadResponse{}, err
}
v.Set("platform", string(p))
query["platform"] = p
}
resp, err := cli.postRaw(ctx, "/images/load", v, input, http.Header{
resp, err := cli.postRaw(ctx, "/images/load", query, input, http.Header{
"Content-Type": {"application/x-tar"},
})
if err != nil {

View File

@ -2,8 +2,6 @@ package client // import "github.com/docker/docker/client"
import (
"context"
"encoding/json"
"fmt"
"io"
"net/url"
@ -17,16 +15,15 @@ func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, opts image.
"names": imageIDs,
}
if opts.Platform != nil {
if len(opts.Platforms) > 0 {
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
return nil, err
}
p, err := json.Marshal(*opts.Platform)
p, err := encodePlatforms(opts.Platforms...)
if err != nil {
return nil, fmt.Errorf("invalid platform: %v", err)
return nil, err
}
query.Set("platform", string(p))
query["platform"] = p
}
resp, err := cli.get(ctx, "/images/get", query, nil)

View File

@ -1,10 +1,14 @@
package client // import "github.com/docker/docker/client"
import (
"encoding/json"
"fmt"
"net/url"
"regexp"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/errdefs"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`)
@ -32,3 +36,43 @@ func getFiltersQuery(f filters.Args) (url.Values, error) {
}
return query, nil
}
// encodePlatforms marshals the given platform(s) to JSON format, to
// be used for query-parameters for filtering / selecting platforms.
func encodePlatforms(platform ...ocispec.Platform) ([]string, error) {
if len(platform) == 0 {
return []string{}, nil
}
if len(platform) == 1 {
p, err := encodePlatform(&platform[0])
if err != nil {
return nil, err
}
return []string{p}, nil
}
seen := make(map[string]struct{}, len(platform))
out := make([]string, 0, len(platform))
for i := range platform {
p, err := encodePlatform(&platform[i])
if err != nil {
return nil, err
}
if _, ok := seen[p]; !ok {
out = append(out, p)
seen[p] = struct{}{}
}
}
return out, nil
}
// encodePlatforms marshals the given platform to JSON format, to
// be used for query-parameters for filtering / selecting platforms. It
// is used as a helper for encodePlatforms,
func encodePlatform(platform *ocispec.Platform) (string, error) {
p, err := json.Marshal(platform)
if err != nil {
return "", errdefs.InvalidParameter(fmt.Errorf("invalid platform: %v", err))
}
return string(p), nil
}

View File

@ -261,13 +261,13 @@ func readdirnames(dirname string) (names []nameIno, err error) {
func parseDirent(buf []byte, names []nameIno) (consumed int, newnames []nameIno) {
origlen := len(buf)
for len(buf) > 0 {
dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0]))
dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0])) // #nosec G103 -- Ignore "G103: Use of unsafe calls should be audited"
buf = buf[dirent.Reclen:]
if dirent.Ino == 0 { // File absent in directory.
continue
}
bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
name := string(bytes[0:clen(bytes[:])])
b := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0])) // #nosec G103 -- Ignore "G103: Use of unsafe calls should be audited"
name := string(b[0:clen(b[:])])
if name == "." || name == ".." { // Useless names
continue
}

View File

@ -22,11 +22,11 @@ type subIDRange struct {
Length int
}
type ranges []subIDRange
type subIDRanges []subIDRange
func (e ranges) Len() int { return len(e) }
func (e ranges) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
func (e ranges) Less(i, j int) bool { return e[i].Start < e[j].Start }
func (e subIDRanges) Len() int { return len(e) }
func (e subIDRanges) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
func (e subIDRanges) Less(i, j int) bool { return e[i].Start < e[j].Start }
const (
subuidFileName = "/etc/subuid"
@ -162,7 +162,7 @@ func (i IdentityMapping) Empty() bool {
return len(i.UIDMaps) == 0 && len(i.GIDMaps) == 0
}
func createIDMap(subidRanges ranges) []IDMap {
func createIDMap(subidRanges subIDRanges) []IDMap {
idMap := []IDMap{}
containerID := 0
@ -177,19 +177,19 @@ func createIDMap(subidRanges ranges) []IDMap {
return idMap
}
func parseSubuid(username string) (ranges, error) {
func parseSubuid(username string) (subIDRanges, error) {
return parseSubidFile(subuidFileName, username)
}
func parseSubgid(username string) (ranges, error) {
func parseSubgid(username string) (subIDRanges, error) {
return parseSubidFile(subgidFileName, username)
}
// parseSubidFile will read the appropriate file (/etc/subuid or /etc/subgid)
// and return all found ranges for a specified username. If the special value
// "ALL" is supplied for username, then all ranges in the file will be returned
func parseSubidFile(path, username string) (ranges, error) {
var rangeList ranges
// and return all found subIDRanges for a specified username. If the special value
// "ALL" is supplied for username, then all subIDRanges in the file will be returned
func parseSubidFile(path, username string) (subIDRanges, error) {
var rangeList subIDRanges
subidFile, err := os.Open(path)
if err != nil {

View File

@ -145,7 +145,7 @@ func findNextGIDRange() (int, error) {
return findNextRangeStart(ranges)
}
func findNextRangeStart(rangeList ranges) (int, error) {
func findNextRangeStart(rangeList subIDRanges) (int, error) {
startID := defaultRangeStart
for _, arange := range rangeList {
if wouldOverlap(arange, startID) {

View File

@ -7,7 +7,7 @@ import (
"strings"
"time"
units "github.com/docker/go-units"
"github.com/docker/go-units"
"github.com/moby/term"
"github.com/morikuni/aec"
)

View File

@ -3,8 +3,8 @@ package system // import "github.com/docker/docker/pkg/system"
// containerdRuntimeSupported determines if containerd should be the runtime.
var containerdRuntimeSupported = false
// InitContainerdRuntime sets whether to use containerd for runtime on Windows.
func InitContainerdRuntime(cdPath string) {
// EnableContainerdRuntime sets whether to use containerd for runtime on Windows.
func EnableContainerdRuntime(cdPath string) {
if len(cdPath) > 0 {
containerdRuntimeSupported = true
}

2
vendor/modules.txt vendored
View File

@ -55,7 +55,7 @@ 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 v27.0.2-0.20241031194140-6ac445c42bad+incompatible
# github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible
## explicit
github.com/docker/docker/api
github.com/docker/docker/api/types