Compare commits

..

1 Commits

Author SHA1 Message Date
Rob Murray 27f3aed907
Merge 81380b9268 into 9861ce90fd 2024-11-18 20:04:48 +02:00
41 changed files with 180 additions and 566 deletions

View File

@ -75,7 +75,7 @@ jobs:
TESTFLAGS: -coverprofile=/tmp/coverage/coverage.txt TESTFLAGS: -coverprofile=/tmp/coverage/coverage.txt
- -
name: Send to Codecov name: Send to Codecov
uses: codecov/codecov-action@v5 uses: codecov/codecov-action@v4
with: with:
files: ./build/coverage/coverage.txt file: ./build/coverage/coverage.txt
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}

View File

@ -40,9 +40,9 @@ jobs:
targets: test-coverage targets: test-coverage
- -
name: Send to Codecov name: Send to Codecov
uses: codecov/codecov-action@v5 uses: codecov/codecov-action@v4
with: with:
files: ./build/coverage/coverage.txt file: ./build/coverage/coverage.txt
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
host: host:
@ -78,8 +78,8 @@ jobs:
shell: bash shell: bash
- -
name: Send to Codecov name: Send to Codecov
uses: codecov/codecov-action@v5 uses: codecov/codecov-action@v4
with: with:
files: /tmp/coverage.txt file: /tmp/coverage.txt
working-directory: ${{ env.GOPATH }}/src/github.com/docker/cli working-directory: ${{ env.GOPATH }}/src/github.com/docker/cli
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}

View File

@ -6,7 +6,7 @@ ARG BASE_DEBIAN_DISTRO=bookworm
ARG GO_VERSION=1.23.3 ARG GO_VERSION=1.23.3
ARG XX_VERSION=1.5.0 ARG XX_VERSION=1.5.0
ARG GOVERSIONINFO_VERSION=v1.4.1 ARG GOVERSIONINFO_VERSION=v1.3.0
ARG GOTESTSUM_VERSION=v1.10.0 ARG GOTESTSUM_VERSION=v1.10.0
ARG BUILDX_VERSION=0.18.0 ARG BUILDX_VERSION=0.18.0
ARG COMPOSE_VERSION=v2.30.3 ARG COMPOSE_VERSION=v2.30.3

View File

@ -287,26 +287,16 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
cStats.mu.RUnlock() cStats.mu.RUnlock()
if !options.NoStream { if !options.NoStream {
// Start by moving the cursor to the top-left // Start by clearing the screen and moving the cursor to the top-left
_, _ = fmt.Fprint(&statsTextBuffer, "\033[H") _, _ = fmt.Fprint(&statsTextBuffer, "\033[2J\033[H")
} }
if err = statsFormatWrite(statsCtx, ccStats, daemonOSType, !options.NoTrunc); err != nil { if err = statsFormatWrite(statsCtx, ccStats, daemonOSType, !options.NoTrunc); err != nil {
break break
} }
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()) _, _ = fmt.Fprint(dockerCLI.Out(), statsTextBuffer.String())
statsTextBuffer.Reset() statsTextBuffer.Reset()
if len(cStats.cs) == 0 && !showAll { if len(cStats.cs) == 0 && !showAll {

View File

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

View File

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

View File

@ -63,8 +63,7 @@ func RunSave(ctx context.Context, dockerCli command.Cli, opts saveOptions) error
if err != nil { if err != nil {
return errors.Wrap(err, "invalid platform") return errors.Wrap(err, "invalid platform")
} }
// TODO(thaJeztah): change flag-type to support multiple platforms. options.Platform = &p
options.Platforms = append(options.Platforms, p)
} }
responseBody, err := dockerCli.Client().ImageSave(ctx, opts.images, options) 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) { imageSaveFunc: func(images []string, options image.SaveOptions) (io.ReadCloser, error) {
assert.Assert(t, is.Len(images, 1)) assert.Assert(t, is.Len(images, 1))
assert.Check(t, is.Equal("arg1", images[0])) assert.Check(t, is.Equal("arg1", images[0]))
assert.Check(t, is.DeepEqual([]ocispec.Platform{{OS: "linux", Architecture: "amd64"}}, options.Platforms)) assert.Check(t, is.DeepEqual(ocispec.Platform{OS: "linux", Architecture: "amd64"}, *options.Platform))
return io.NopCloser(strings.NewReader("")), nil return io.NopCloser(strings.NewReader("")), nil
}, },
}, },

View File

@ -2,7 +2,7 @@
ARG GO_VERSION=1.23.3 ARG GO_VERSION=1.23.3
ARG ALPINE_VERSION=3.20 ARG ALPINE_VERSION=3.20
ARG GOLANGCI_LINT_VERSION=v1.62.0 ARG GOLANGCI_LINT_VERSION=v1.61.0
FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint

View File

@ -13,20 +13,20 @@ require (
github.com/distribution/reference v0.6.0 github.com/distribution/reference v0.6.0
github.com/docker/cli-docs-tool v0.8.0 github.com/docker/cli-docs-tool v0.8.0
github.com/docker/distribution v2.8.3+incompatible github.com/docker/distribution v2.8.3+incompatible
github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible // master (v-next) github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible // master (v-next)
github.com/docker/docker-credential-helpers v0.8.2 github.com/docker/docker-credential-helpers v0.8.2
github.com/docker/go-connections v0.5.0 github.com/docker/go-connections v0.5.0
github.com/docker/go-units v0.5.0 github.com/docker/go-units v0.5.0
github.com/fvbommel/sortorder v1.1.0 github.com/fvbommel/sortorder v1.1.0
github.com/go-jose/go-jose/v4 v4.0.4 github.com/go-jose/go-jose/v4 v4.0.4
github.com/go-viper/mapstructure/v2 v2.2.1 github.com/go-viper/mapstructure/v2 v2.0.0
github.com/gogo/protobuf v1.3.2 github.com/gogo/protobuf v1.3.2
github.com/google/go-cmp v0.6.0 github.com/google/go-cmp v0.6.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/mattn/go-runewidth v0.0.15 github.com/mattn/go-runewidth v0.0.15
github.com/moby/patternmatcher v0.6.0 github.com/moby/patternmatcher v0.6.0
github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e
github.com/moby/sys/capability v0.4.0 github.com/moby/sys/capability v0.3.0
github.com/moby/sys/sequential v0.6.0 github.com/moby/sys/sequential v0.6.0
github.com/moby/sys/signal v0.7.1 github.com/moby/sys/signal v0.7.1
github.com/moby/term v0.5.0 github.com/moby/term v0.5.0
@ -39,7 +39,7 @@ require (
github.com/spf13/cobra v1.8.1 github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a
github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d
github.com/xeipuuv/gojsonschema v1.2.0 github.com/xeipuuv/gojsonschema v1.2.0
go.opentelemetry.io/otel v1.28.0 go.opentelemetry.io/otel v1.28.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.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.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible h1:ZWh4HhdUCagAd3S+gsFPOobHbc562obYFSrz3irGSsU= github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible h1:kSQ4U+63JfFxIOrTo6wMW1mqkOkPpiTe/7ZfvUdNLVE=
github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
@ -89,8 +89,8 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@ -168,8 +168,8 @@ github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkV
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e h1:1yC8fRqStY6NirU/swI74fsrHvZVMbtxsHcvl8YpzDg= github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e h1:1yC8fRqStY6NirU/swI74fsrHvZVMbtxsHcvl8YpzDg=
github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e/go.mod h1:mTTGIAz/59OGZR5Qe+QByIe3Nxc+sSuJkrsStFhr6Lg= github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e/go.mod h1:mTTGIAz/59OGZR5Qe+QByIe3Nxc+sSuJkrsStFhr6Lg=
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk= github.com/moby/sys/capability v0.3.0 h1:kEP+y6te0gEXIaeQhIi0s7vKs/w0RPoH1qPa6jROcVg=
github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I= github.com/moby/sys/capability v0.3.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0= github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
@ -266,8 +266,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a h1:tlJ7tGUHvcvL1v3yR6NcCc9nOqh2L+CG6HWrYQtwzQ0= github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a h1:tlJ7tGUHvcvL1v3yR6NcCc9nOqh2L+CG6HWrYQtwzQ0=
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a/go.mod h1:Y94A6rPp2OwNfP/7vmf8O2xx2IykP8pPXQ1DLouGnEw= github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a/go.mod h1:Y94A6rPp2OwNfP/7vmf8O2xx2IykP8pPXQ1DLouGnEw=
github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 h1:TvtdmeYsYEij78hS4oxnwikoiLdIrgav3BA+CbhaDAI= github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d h1:wvQZpqy8p0D/FUia6ipKDhXrzPzBVJE4PZyPc5+5Ay0=
github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346/go.mod h1:xKQhd7snlzKFuUi1taTGWjpRE8iFTA06DeacYi3CVFQ= github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d/go.mod h1:xKQhd7snlzKFuUi1taTGWjpRE8iFTA06DeacYi3CVFQ=
github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b h1:FsyNrX12e5BkplJq7wKOLk0+C6LZ+KGXvuEcKUYm5ss= github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b h1:FsyNrX12e5BkplJq7wKOLk0+C6LZ+KGXvuEcKUYm5ss=
github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=

View File

@ -1991,18 +1991,6 @@ definitions:
type: "string" type: "string"
x-nullable: false x-nullable: false
example: "sha256:ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710" 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: RepoTags:
description: | description: |
List of image names/tags in the local image cache that reference this List of image names/tags in the local image cache that reference this
@ -2290,18 +2278,6 @@ definitions:
x-omitempty: true x-omitempty: true
items: items:
$ref: "#/definitions/ImageManifestSummary" $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: AuthConfig:
type: "object" type: "object"
@ -7266,14 +7242,6 @@ paths:
type: "string" type: "string"
Platform: Platform:
type: "string" 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: MountLabel:
type: "string" type: "string"
ProcessLabel: ProcessLabel:
@ -9242,14 +9210,9 @@ paths:
type: "string" type: "string"
in: "query" in: "query"
description: | description: |
JSON-encoded OCI platform to select the platform-variant. JSON encoded OCI platform describing platform to show the history for.
If omitted, it defaults to any locally available platform, If not provided, the host platform will be used. If it's not
prioritizing the daemon's host platform. available, any present platform will be picked.
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"}` Example: `{"os": "linux", "architecture": "arm", "variant": "v5"}`
tags: ["Image"] tags: ["Image"]
@ -9299,19 +9262,6 @@ paths:
all tags of the given image that are present in the local image store all tags of the given image that are present in the local image store
are pushed. are pushed.
type: "string" 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" - name: "X-Registry-Auth"
in: "header" in: "header"
description: | description: |
@ -9321,6 +9271,11 @@ paths:
details. details.
type: "string" type: "string"
required: true 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"] tags: ["Image"]
/images/{name}/tag: /images/{name}/tag:
post: post:

View File

@ -7,7 +7,6 @@ import (
"github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/storage" "github.com/docker/docker/api/types/storage"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
) )
// PruneReport contains the response for Engine API: // PruneReport contains the response for Engine API:
@ -172,6 +171,4 @@ type InspectResponse struct {
Mounts []MountPoint Mounts []MountPoint
Config *Config Config *Config
NetworkSettings *NetworkSettings 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/network"
"github.com/docker/docker/api/types/strslice" "github.com/docker/docker/api/types/strslice"
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
"github.com/docker/go-units" units "github.com/docker/go-units"
) )
// CgroupnsMode represents the cgroup namespace mode of the container // CgroupnsMode represents the cgroup namespace mode of the container

View File

@ -3,7 +3,6 @@ package image
import ( import (
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/storage" "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. // RootFS returns Image's RootFS description including the layer IDs.
@ -120,11 +119,4 @@ type InspectResponse struct {
// //
// This information is local to the daemon, and not part of the image itself. // This information is local to the daemon, and not part of the image itself.
Metadata Metadata 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,14 +98,12 @@ type LoadOptions struct {
// Quiet suppresses progress output // Quiet suppresses progress output
Quiet bool Quiet bool
// Platforms selects the platforms to load if the image is a // Platform is a specific platform to load when the image is a multi-platform
// multi-platform image and has multiple variants. Platform *ocispec.Platform
Platforms []ocispec.Platform
} }
// SaveOptions holds parameters to save images. // SaveOptions holds parameters to save images.
type SaveOptions struct { type SaveOptions struct {
// Platforms selects the platforms to save if the image is a // Platform is a specific platform to save if the image is a multi-platform image.
// multi-platform image and has multiple variants. Platform *ocispec.Platform
Platforms []ocispec.Platform
} }

View File

@ -1,7 +1,5 @@
package image package image
import ocispec "github.com/opencontainers/image-spec/specs-go/v1"
type Summary struct { type Summary struct {
// Number of containers using this image. Includes both stopped and running // Number of containers using this image. Includes both stopped and running
@ -44,13 +42,6 @@ type Summary struct {
// Required: true // Required: true
ParentID string `json:"ParentId"` 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 // Manifests is a list of image manifests available in this image. It
// provides a more detailed view of the platform-specific image manifests or // provides a more detailed view of the platform-specific image manifests or
// other image-attached data like build attestations. // other image-attached data like build attestations.

View File

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

View File

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

View File

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

View File

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

View File

@ -1,14 +1,10 @@
package client // import "github.com/docker/docker/client" package client // import "github.com/docker/docker/client"
import ( import (
"encoding/json"
"fmt"
"net/url" "net/url"
"regexp" "regexp"
"github.com/docker/docker/api/types/filters" "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`) var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`)
@ -36,43 +32,3 @@ func getFiltersQuery(f filters.Args) (url.Values, error) {
} }
return query, nil 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) { func parseDirent(buf []byte, names []nameIno) (consumed int, newnames []nameIno) {
origlen := len(buf) origlen := len(buf)
for len(buf) > 0 { for len(buf) > 0 {
dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0])) // #nosec G103 -- Ignore "G103: Use of unsafe calls should be audited" dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0]))
buf = buf[dirent.Reclen:] buf = buf[dirent.Reclen:]
if dirent.Ino == 0 { // File absent in directory. if dirent.Ino == 0 { // File absent in directory.
continue continue
} }
b := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0])) // #nosec G103 -- Ignore "G103: Use of unsafe calls should be audited" bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
name := string(b[0:clen(b[:])]) name := string(bytes[0:clen(bytes[:])])
if name == "." || name == ".." { // Useless names if name == "." || name == ".." { // Useless names
continue continue
} }

View File

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

View File

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

View File

@ -7,7 +7,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/docker/go-units" units "github.com/docker/go-units"
"github.com/moby/term" "github.com/moby/term"
"github.com/morikuni/aec" "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. // containerdRuntimeSupported determines if containerd should be the runtime.
var containerdRuntimeSupported = false var containerdRuntimeSupported = false
// EnableContainerdRuntime sets whether to use containerd for runtime on Windows. // InitContainerdRuntime sets whether to use containerd for runtime on Windows.
func EnableContainerdRuntime(cdPath string) { func InitContainerdRuntime(cdPath string) {
if len(cdPath) > 0 { if len(cdPath) > 0 {
containerdRuntimeSupported = true containerdRuntimeSupported = true
} }

View File

@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"net" "net"
"net/netip" "net/netip"
"net/url"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
@ -37,30 +36,6 @@ func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
return nil return nil
} }
// cachedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns
// it into a closure to be used directly
// if the type fails to convert we return a closure always erroring to keep the previous behaviour
func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (interface{}, error) {
switch f := typedDecodeHook(raw).(type) {
case DecodeHookFuncType:
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
return f(from.Type(), to.Type(), from.Interface())
}
case DecodeHookFuncKind:
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
return f(from.Kind(), to.Kind(), from.Interface())
}
case DecodeHookFuncValue:
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
return f(from, to)
}
default:
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
return nil, errors.New("invalid decode hook signature")
}
}
}
// DecodeHookExec executes the given decode hook. This should be used // DecodeHookExec executes the given decode hook. This should be used
// since it'll naturally degrade to the older backwards compatible DecodeHookFunc // since it'll naturally degrade to the older backwards compatible DecodeHookFunc
// that took reflect.Kind instead of reflect.Type. // that took reflect.Kind instead of reflect.Type.
@ -86,17 +61,13 @@ func DecodeHookExec(
// The composed funcs are called in order, with the result of the // The composed funcs are called in order, with the result of the
// previous transformation. // previous transformation.
func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(fs))
for _, f := range fs {
cached = append(cached, cachedDecodeHook(f))
}
return func(f reflect.Value, t reflect.Value) (interface{}, error) { return func(f reflect.Value, t reflect.Value) (interface{}, error) {
var err error var err error
data := f.Interface() data := f.Interface()
newFrom := f newFrom := f
for _, c := range cached { for _, f1 := range fs {
data, err = c(newFrom, t) data, err = DecodeHookExec(f1, newFrom, t)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -110,17 +81,13 @@ func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned. // OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages. // If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc { func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc {
cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(ff))
for _, f := range ff {
cached = append(cached, cachedDecodeHook(f))
}
return func(a, b reflect.Value) (interface{}, error) { return func(a, b reflect.Value) (interface{}, error) {
var allErrs string var allErrs string
var out interface{} var out interface{}
var err error var err error
for _, c := range cached { for _, f := range ff {
out, err = c(a, b) out, err = DecodeHookExec(f, a, b)
if err != nil { if err != nil {
allErrs += err.Error() + "\n" allErrs += err.Error() + "\n"
continue continue
@ -177,26 +144,6 @@ func StringToTimeDurationHookFunc() DecodeHookFunc {
} }
} }
// StringToURLHookFunc returns a DecodeHookFunc that converts
// strings to *url.URL.
func StringToURLHookFunc() DecodeHookFunc {
return func(
f reflect.Type,
t reflect.Type,
data interface{},
) (interface{}, error) {
if f.Kind() != reflect.String {
return data, nil
}
if t != reflect.TypeOf(&url.URL{}) {
return data, nil
}
// Convert it by parsing
return url.Parse(data.(string))
}
}
// StringToIPHookFunc returns a DecodeHookFunc that converts // StringToIPHookFunc returns a DecodeHookFunc that converts
// strings to net.IP // strings to net.IP
func StringToIPHookFunc() DecodeHookFunc { func StringToIPHookFunc() DecodeHookFunc {

View File

@ -266,10 +266,6 @@ type DecoderConfig struct {
// defaults to "mapstructure" // defaults to "mapstructure"
TagName string TagName string
// The option of the value in the tag that indicates a field should
// be squashed. This defaults to "squash".
SquashTagOption string
// IgnoreUntaggedFields ignores all struct fields without explicit // IgnoreUntaggedFields ignores all struct fields without explicit
// TagName, comparable to `mapstructure:"-"` as default behaviour. // TagName, comparable to `mapstructure:"-"` as default behaviour.
IgnoreUntaggedFields bool IgnoreUntaggedFields bool
@ -278,10 +274,6 @@ type DecoderConfig struct {
// field name or tag. Defaults to `strings.EqualFold`. This can be used // field name or tag. Defaults to `strings.EqualFold`. This can be used
// to implement case-sensitive tag values, support snake casing, etc. // to implement case-sensitive tag values, support snake casing, etc.
MatchName func(mapKey, fieldName string) bool MatchName func(mapKey, fieldName string) bool
// DecodeNil, if set to true, will cause the DecodeHook (if present) to run
// even if the input is nil. This can be used to provide default values.
DecodeNil bool
} }
// A Decoder takes a raw interface value and turns it into structured // A Decoder takes a raw interface value and turns it into structured
@ -292,7 +284,6 @@ type DecoderConfig struct {
// up the most basic Decoder. // up the most basic Decoder.
type Decoder struct { type Decoder struct {
config *DecoderConfig config *DecoderConfig
cachedDecodeHook func(from reflect.Value, to reflect.Value) (interface{}, error)
} }
// Metadata contains information about decoding a structure that // Metadata contains information about decoding a structure that
@ -410,10 +401,6 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
config.TagName = "mapstructure" config.TagName = "mapstructure"
} }
if config.SquashTagOption == "" {
config.SquashTagOption = "squash"
}
if config.MatchName == nil { if config.MatchName == nil {
config.MatchName = strings.EqualFold config.MatchName = strings.EqualFold
} }
@ -421,9 +408,6 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
result := &Decoder{ result := &Decoder{
config: config, config: config,
} }
if config.DecodeHook != nil {
result.cachedDecodeHook = cachedDecodeHook(config.DecodeHook)
}
return result, nil return result, nil
} }
@ -442,26 +426,19 @@ func (d *Decoder) Decode(input interface{}) error {
return err return err
} }
// isNil returns true if the input is nil or a typed nil pointer.
func isNil(input interface{}) bool {
if input == nil {
return true
}
val := reflect.ValueOf(input)
return val.Kind() == reflect.Ptr && val.IsNil()
}
// Decodes an unknown data type into a specific reflection value. // Decodes an unknown data type into a specific reflection value.
func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error { func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error {
var ( var inputVal reflect.Value
if input != nil {
inputVal = reflect.ValueOf(input) inputVal = reflect.ValueOf(input)
outputKind = getKind(outVal)
decodeNil = d.config.DecodeNil && d.cachedDecodeHook != nil // We need to check here if input is a typed nil. Typed nils won't
) // match the "input == nil" below so we check that here.
if isNil(input) { if inputVal.Kind() == reflect.Ptr && inputVal.IsNil() {
// Typed nils won't match the "input == nil" below, so reset input.
input = nil input = nil
} }
}
if input == nil { if input == nil {
// If the data is nil, then we don't set anything, unless ZeroFields is set // If the data is nil, then we don't set anything, unless ZeroFields is set
// to true. // to true.
@ -472,12 +449,10 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
} }
} }
if !decodeNil {
return nil return nil
} }
}
if !inputVal.IsValid() { if !inputVal.IsValid() {
if !decodeNil {
// If the input value is invalid, then we just set the value // If the input value is invalid, then we just set the value
// to be the zero value. // to be the zero value.
outVal.Set(reflect.Zero(outVal.Type())) outVal.Set(reflect.Zero(outVal.Type()))
@ -486,32 +461,18 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
} }
return nil return nil
} }
// Hooks need a valid inputVal, so reset it to zero value of outVal type.
switch outputKind {
case reflect.Struct, reflect.Map:
var mapVal map[string]interface{}
inputVal = reflect.ValueOf(mapVal) // create nil map pointer
case reflect.Slice, reflect.Array:
var sliceVal []interface{}
inputVal = reflect.ValueOf(sliceVal) // create nil slice pointer
default:
inputVal = reflect.Zero(outVal.Type())
}
}
if d.cachedDecodeHook != nil { if d.config.DecodeHook != nil {
// We have a DecodeHook, so let's pre-process the input. // We have a DecodeHook, so let's pre-process the input.
var err error var err error
input, err = d.cachedDecodeHook(inputVal, outVal) input, err = DecodeHookExec(d.config.DecodeHook, inputVal, outVal)
if err != nil { if err != nil {
return fmt.Errorf("error decoding '%s': %w", name, err) return fmt.Errorf("error decoding '%s': %w", name, err)
} }
} }
if isNil(input) {
return nil
}
var err error var err error
outputKind := getKind(outVal)
addMetaKey := true addMetaKey := true
switch outputKind { switch outputKind {
case reflect.Bool: case reflect.Bool:
@ -792,8 +753,8 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e
} }
default: default:
return fmt.Errorf( return fmt.Errorf(
"'%s' expected type '%s', got unconvertible type '%#v', value: '%#v'", "'%s' expected type '%s', got unconvertible type '%s', value: '%v'",
name, val, dataVal, data) name, val.Type(), dataVal.Type(), data)
} }
return nil return nil
@ -1012,7 +973,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
} }
// If "squash" is specified in the tag, we squash the field down. // If "squash" is specified in the tag, we squash the field down.
squash = squash || strings.Contains(tagValue[index+1:], d.config.SquashTagOption) squash = squash || strings.Index(tagValue[index+1:], "squash") != -1
if squash { if squash {
// When squashing, the embedded type can be a pointer to a struct. // When squashing, the embedded type can be a pointer to a struct.
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
@ -1390,7 +1351,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
// We always parse the tags cause we're looking for other tags too // We always parse the tags cause we're looking for other tags too
tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",") tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
for _, tag := range tagParts[1:] { for _, tag := range tagParts[1:] {
if tag == d.config.SquashTagOption { if tag == "squash" {
squash = true squash = true
break break
} }
@ -1402,15 +1363,10 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
} }
if squash { if squash {
switch fieldVal.Kind() { if fieldVal.Kind() != reflect.Struct {
case reflect.Struct:
structs = append(structs, fieldVal)
case reflect.Interface:
if !fieldVal.IsNil() {
structs = append(structs, fieldVal.Elem().Elem())
}
default:
errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind())) errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind()))
} else {
structs = append(structs, fieldVal)
} }
continue continue
} }

3
vendor/github.com/moby/sys/capability/.codespellrc generated vendored Normal file
View File

@ -0,0 +1,3 @@
[codespell]
skip = ./.git
ignore-words-list = nd

6
vendor/github.com/moby/sys/capability/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,6 @@
linters:
enable:
- unconvert
- unparam
- gofumpt
- errorlint

View File

@ -5,30 +5,6 @@ from https://github.com/syndtr/gocapability/commit/42c35b4376354fd5.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.4.0] - 2024-11-11
### Added
* New separate API for ambient ([GetAmbient], [SetAmbient], [ResetAmbient])
and bound ([GetBound], [DropBound]) capabilities, modelled after libcap. (#176)
### Fixed
* [Apply] now returns an error if called for non-zero `pid`. Before this change,
it could silently change some capabilities of the current process, instead of
the one identified by the `pid`. (#168, #174)
* Fixed tests that change capabilities to be run in a separate process. (#173)
* Other improvements in tests. (#169, #170)
### Changed
* Use raw syscalls (which are slightly faster). (#176)
* Most tests are now limited to testing the public API of the package. (#162)
* Simplify parsing /proc/*pid*/status, add a test case. (#162)
* Optimize the number of syscall to set ambient capabilities in Apply
by clearing them first; add a test case. (#163, #164)
* Better documentation for [Apply], [NewFile], [NewFile2], [NewPid], [NewPid2]. (#175)
### Removed
* `.golangci.yml` and `.codespellrc` are no longer part of the package. (#158)
## [0.3.0] - 2024-09-25 ## [0.3.0] - 2024-09-25
### Added ### Added
@ -87,24 +63,14 @@ This is an initial release since the fork.
* Removed init function so programs that use this package start faster. [#6] * Removed init function so programs that use this package start faster. [#6]
* Removed `CAP_LAST_CAP` (use [LastCap] instead). [#6] * Removed `CAP_LAST_CAP` (use [LastCap] instead). [#6]
<!-- Doc links (please keep sorted). --> <!-- Doc links. -->
[Apply]: https://pkg.go.dev/github.com/moby/sys/capability#Capabilities.Apply [Apply]: https://pkg.go.dev/github.com/moby/sys/capability#Capabilities.Apply
[DropBound]: https://pkg.go.dev/github.com/moby/sys/capability#DropBound
[GetAmbient]: https://pkg.go.dev/github.com/moby/sys/capability#GetAmbient
[GetBound]: https://pkg.go.dev/github.com/moby/sys/capability#GetBound
[LastCap]: https://pkg.go.dev/github.com/moby/sys/capability#LastCap [LastCap]: https://pkg.go.dev/github.com/moby/sys/capability#LastCap
[List]: https://pkg.go.dev/github.com/moby/sys/capability#List
[ListKnown]: https://pkg.go.dev/github.com/moby/sys/capability#ListKnown [ListKnown]: https://pkg.go.dev/github.com/moby/sys/capability#ListKnown
[ListSupported]: https://pkg.go.dev/github.com/moby/sys/capability#ListSupported [ListSupported]: https://pkg.go.dev/github.com/moby/sys/capability#ListSupported
[List]: https://pkg.go.dev/github.com/moby/sys/capability#List
[NewFile2]: https://pkg.go.dev/github.com/moby/sys/capability#NewFile2
[NewFile]: https://pkg.go.dev/github.com/moby/sys/capability#NewFile
[NewPid2]: https://pkg.go.dev/github.com/moby/sys/capability#NewPid2
[NewPid]: https://pkg.go.dev/github.com/moby/sys/capability#NewPid
[ResetAmbient]: https://pkg.go.dev/github.com/moby/sys/capability#ResetAmbient
[SetAmbient]: https://pkg.go.dev/github.com/moby/sys/capability#SetAmbient
<!-- Minor releases. --> <!-- Minor releases. -->
[0.4.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.4.0
[0.3.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.3.0 [0.3.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.3.0
[0.2.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.2.0 [0.2.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.2.0
[0.1.1]: https://github.com/kolyshkin/capability/compare/v0.1.0...v0.1.1 [0.1.1]: https://github.com/kolyshkin/capability/compare/v0.1.0...v0.1.1

View File

@ -56,16 +56,16 @@ type Capabilities interface {
// outstanding changes. // outstanding changes.
Load() error Load() error
// Apply apply the capabilities settings, so all changes made by // Apply apply the capabilities settings, so all changes will take
// [Set], [Unset], [Fill], or [Clear] will take effect. // effect.
Apply(kind CapType) error Apply(kind CapType) error
} }
// NewPid initializes a new [Capabilities] object for given pid when // NewPid initializes a new [Capabilities] object for given pid when
// it is nonzero, or for the current process if pid is 0. // it is nonzero, or for the current process if pid is 0.
// //
// Deprecated: replace with [NewPid2] followed by optional [Capabilities.Load] // Deprecated: Replace with [NewPid2] followed by [Capabilities.Load].
// (only if needed). For example, replace: // For example, replace:
// //
// c, err := NewPid(0) // c, err := NewPid(0)
// if err != nil { // if err != nil {
@ -93,16 +93,16 @@ func NewPid(pid int) (Capabilities, error) {
// NewPid2 initializes a new [Capabilities] object for given pid when // NewPid2 initializes a new [Capabilities] object for given pid when
// it is nonzero, or for the current process if pid is 0. This // it is nonzero, or for the current process if pid is 0. This
// does not load the process's current capabilities; if needed, // does not load the process's current capabilities; to do that you
// call [Capabilities.Load]. // must call [Capabilities.Load] explicitly.
func NewPid2(pid int) (Capabilities, error) { func NewPid2(pid int) (Capabilities, error) {
return newPid(pid) return newPid(pid)
} }
// NewFile initializes a new Capabilities object for given file path. // NewFile initializes a new Capabilities object for given file path.
// //
// Deprecated: replace with [NewFile2] followed by optional [Capabilities.Load] // Deprecated: Replace with [NewFile2] followed by [Capabilities.Load].
// (only if needed). For example, replace: // For example, replace:
// //
// c, err := NewFile(path) // c, err := NewFile(path)
// if err != nil { // if err != nil {
@ -130,7 +130,7 @@ func NewFile(path string) (Capabilities, error) {
// NewFile2 creates a new initialized [Capabilities] object for given // NewFile2 creates a new initialized [Capabilities] object for given
// file path. This does not load the process's current capabilities; // file path. This does not load the process's current capabilities;
// if needed, call [Capabilities.Load]. // to do that you must call [Capabilities.Load] explicitly.
func NewFile2(path string) (Capabilities, error) { func NewFile2(path string) (Capabilities, error) {
return newFile(path) return newFile(path)
} }
@ -142,35 +142,3 @@ func NewFile2(path string) (Capabilities, error) {
func LastCap() (Cap, error) { func LastCap() (Cap, error) {
return lastCap() return lastCap()
} }
// GetAmbient determines if a specific ambient capability is raised in the
// calling thread.
func GetAmbient(c Cap) (bool, error) {
return getAmbient(c)
}
// SetAmbient raises or lowers specified ambient capabilities for the calling
// thread. To complete successfully, the prevailing effective capability set
// must have a raised CAP_SETPCAP. Further, to raise a specific ambient
// capability the inheritable and permitted sets of the calling thread must
// already contain the specified capability.
func SetAmbient(raise bool, caps ...Cap) error {
return setAmbient(raise, caps...)
}
// ResetAmbient resets all of the ambient capabilities for the calling thread
// to their lowered value.
func ResetAmbient() error {
return resetAmbient()
}
// GetBound determines if a specific bounding capability is raised in the
// calling thread.
func GetBound(c Cap) (bool, error) {
return getBound(c)
}
// DropBound lowers the specified bounding set capability.
func DropBound(caps ...Cap) error {
return dropBound(caps...)
}

View File

@ -117,13 +117,6 @@ func newPid(pid int) (c Capabilities, retErr error) {
return return
} }
func ignoreEINVAL(err error) error {
if errors.Is(err, syscall.EINVAL) {
err = nil
}
return err
}
type capsV3 struct { type capsV3 struct {
hdr capHeader hdr capHeader
data [2]capData data [2]capData
@ -314,15 +307,15 @@ func (c *capsV3) Load() (err error) {
} }
break break
} }
if val, ok := strings.CutPrefix(line, "CapBnd:\t"); ok { if strings.HasPrefix(line, "CapB") {
_, err = fmt.Sscanf(val, "%08x%08x", &c.bounds[1], &c.bounds[0]) _, err = fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0])
if err != nil { if err != nil {
break break
} }
continue continue
} }
if val, ok := strings.CutPrefix(line, "CapAmb:\t"); ok { if strings.HasPrefix(line, "CapA") {
_, err = fmt.Sscanf(val, "%08x%08x", &c.ambient[1], &c.ambient[0]) _, err = fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0])
if err != nil { if err != nil {
break break
} }
@ -334,10 +327,7 @@ func (c *capsV3) Load() (err error) {
return return
} }
func (c *capsV3) Apply(kind CapType) error { func (c *capsV3) Apply(kind CapType) (err error) {
if c.hdr.pid != 0 {
return errors.New("unable to modify capabilities of another process")
}
last, err := LastCap() last, err := LastCap()
if err != nil { if err != nil {
return err return err
@ -346,17 +336,21 @@ func (c *capsV3) Apply(kind CapType) error {
var data [2]capData var data [2]capData
err = capget(&c.hdr, &data[0]) err = capget(&c.hdr, &data[0])
if err != nil { if err != nil {
return err return
} }
if (1<<uint(CAP_SETPCAP))&data[0].effective != 0 { if (1<<uint(CAP_SETPCAP))&data[0].effective != 0 {
for i := Cap(0); i <= last; i++ { for i := Cap(0); i <= last; i++ {
if c.Get(BOUNDING, i) { if c.Get(BOUNDING, i) {
continue continue
} }
// Ignore EINVAL since the capability may not be supported in this system. err = prctl(syscall.PR_CAPBSET_DROP, uintptr(i), 0, 0, 0)
err = ignoreEINVAL(dropBound(i))
if err != nil { if err != nil {
return err // Ignore EINVAL since the capability may not be supported in this system.
if err == syscall.EINVAL { //nolint:errorlint // Errors from syscall are bare.
err = nil
continue
}
return
} }
} }
} }
@ -365,73 +359,29 @@ func (c *capsV3) Apply(kind CapType) error {
if kind&CAPS == CAPS { if kind&CAPS == CAPS {
err = capset(&c.hdr, &c.data[0]) err = capset(&c.hdr, &c.data[0])
if err != nil { if err != nil {
return err return
} }
} }
if kind&AMBS == AMBS { if kind&AMBS == AMBS {
// Ignore EINVAL as not supported on kernels before 4.3
err = ignoreEINVAL(resetAmbient())
if err != nil {
return err
}
for i := Cap(0); i <= last; i++ { for i := Cap(0); i <= last; i++ {
if !c.Get(AMBIENT, i) { action := pr_CAP_AMBIENT_LOWER
if c.Get(AMBIENT, i) {
action = pr_CAP_AMBIENT_RAISE
}
err = prctl(pr_CAP_AMBIENT, action, uintptr(i), 0, 0)
if err != nil {
// Ignore EINVAL as not supported on kernels before 4.3
if err == syscall.EINVAL { //nolint:errorlint // Errors from syscall are bare.
err = nil
continue continue
} }
// Ignore EINVAL as not supported on kernels before 4.3 return
err = ignoreEINVAL(setAmbient(true, i))
if err != nil {
return err
} }
} }
} }
return nil return
}
func getAmbient(c Cap) (bool, error) {
res, err := prctlRetInt(pr_CAP_AMBIENT, pr_CAP_AMBIENT_IS_SET, uintptr(c))
if err != nil {
return false, err
}
return res > 0, nil
}
func setAmbient(raise bool, caps ...Cap) error {
op := pr_CAP_AMBIENT_RAISE
if !raise {
op = pr_CAP_AMBIENT_LOWER
}
for _, val := range caps {
err := prctl(pr_CAP_AMBIENT, op, uintptr(val))
if err != nil {
return err
}
}
return nil
}
func resetAmbient() error {
return prctl(pr_CAP_AMBIENT, pr_CAP_AMBIENT_CLEAR_ALL, 0)
}
func getBound(c Cap) (bool, error) {
res, err := prctlRetInt(syscall.PR_CAPBSET_READ, uintptr(c), 0)
if err != nil {
return false, err
}
return res > 0, nil
}
func dropBound(caps ...Cap) error {
for _, val := range caps {
err := prctl(syscall.PR_CAPBSET_DROP, uintptr(val), 0)
if err != nil {
return err
}
}
return nil
} }
func newFile(path string) (c Capabilities, err error) { func newFile(path string) (c Capabilities, err error) {

View File

@ -24,23 +24,3 @@ func newFile(_ string) (Capabilities, error) {
func lastCap() (Cap, error) { func lastCap() (Cap, error) {
return -1, errNotSup return -1, errNotSup
} }
func getAmbient(_ Cap) (bool, error) {
return false, errNotSup
}
func setAmbient(_ bool, _ ...Cap) error {
return errNotSup
}
func resetAmbient() error {
return errNotSup
}
func getBound(_ Cap) (bool, error) {
return false, errNotSup
}
func dropBound(_ ...Cap) error {
return errNotSup
}

View File

@ -316,7 +316,7 @@ func ListKnown() []Cap {
return list() return list()
} }
// ListSupported returns the list of all capabilities known to the package, // ListSupported retuns the list of all capabilities known to the package,
// except those that are not supported by the currently running Linux kernel. // except those that are not supported by the currently running Linux kernel.
func ListSupported() ([]Cap, error) { func ListSupported() ([]Cap, error) {
last, err := LastCap() last, err := LastCap()

View File

@ -24,7 +24,7 @@ type capData struct {
} }
func capget(hdr *capHeader, data *capData) (err error) { func capget(hdr *capHeader, data *capData) (err error) {
_, _, e1 := syscall.RawSyscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) _, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
if e1 != 0 { if e1 != 0 {
err = e1 err = e1
} }
@ -32,7 +32,7 @@ func capget(hdr *capHeader, data *capData) (err error) {
} }
func capset(hdr *capHeader, data *capData) (err error) { func capset(hdr *capHeader, data *capData) (err error) {
_, _, e1 := syscall.RawSyscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) _, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
if e1 != 0 { if e1 != 0 {
err = e1 err = e1
} }
@ -48,22 +48,14 @@ const (
pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4) pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4)
) )
func prctl(option int, arg2, arg3 uintptr) (err error) { func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
_, _, e1 := syscall.RawSyscall(syscall.SYS_PRCTL, uintptr(option), arg2, arg3) _, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0)
if e1 != 0 { if e1 != 0 {
err = e1 err = e1
} }
return return
} }
func prctlRetInt(option int, arg2, arg3 uintptr) (int, error) {
ret, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, uintptr(option), arg2, arg3)
if err != 0 {
return 0, err
}
return int(ret), nil
}
const ( const (
vfsXattrName = "security.capability" vfsXattrName = "security.capability"
@ -100,7 +92,7 @@ func getVfsCap(path string, dest *vfscapData) (err error) {
if err != nil { if err != nil {
return return
} }
r0, _, e1 := syscall.RawSyscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0) r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0)
if e1 != 0 { if e1 != 0 {
if e1 == syscall.ENODATA { if e1 == syscall.ENODATA {
dest.version = 2 dest.version = 2
@ -153,7 +145,7 @@ func setVfsCap(path string, data *vfscapData) (err error) {
} else { } else {
return syscall.EINVAL return syscall.EINVAL
} }
_, _, e1 := syscall.RawSyscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0) _, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0)
if e1 != 0 { if e1 != 0 {
err = e1 err = e1
} }

View File

@ -1,8 +0,0 @@
go-rosetta
==========
[![PkgGoDev](https://pkg.go.dev/badge/github.com/tonistiigi/go-rosetta)](https://pkg.go.dev/github.com/tonistiigi/go-rosetta)
`go-rosetta` provides utilities to detect if an application is running as a
[Rosetta](https://developer.apple.com/documentation/apple_silicon/about_the_rosetta_translation_environment) translated binary, and
to determine the native architecture.

View File

@ -1,28 +1,17 @@
//go:build darwin
// +build darwin // +build darwin
package rosetta package rosetta
import ( import (
"os"
"runtime" "runtime"
"syscall" "syscall"
) )
// Available returns true if Rosetta is installed/available
func Available() bool {
_, err := os.Stat("/Library/Apple/usr/share/rosetta")
return err == nil
}
// Enabled returns true if running in a Rosetta Translated Binary, false otherwise.
func Enabled() bool { func Enabled() bool {
v, err := syscall.SysctlUint32("sysctl.proc_translated") v, err := syscall.SysctlUint32("sysctl.proc_translated")
return err == nil && v == 1 return err == nil && v == 1
} }
// NativeArch returns the native architecture, even if binary architecture
// is emulated by Rosetta.
func NativeArch() string { func NativeArch() string {
if Enabled() && runtime.GOARCH == "amd64" { if Enabled() && runtime.GOARCH == "amd64" {
return "arm64" return "arm64"

View File

@ -1,4 +1,3 @@
//go:build !darwin
// +build !darwin // +build !darwin
package rosetta package rosetta
@ -7,18 +6,10 @@ import (
"runtime" "runtime"
) )
// Available returns true if Rosetta is installed/available
func Available() bool {
return false
}
// Enabled returns true if running in a Rosetta Translated Binary, false otherwise.
func Enabled() bool { func Enabled() bool {
return false return false
} }
// NativeArch returns the native architecture, even if binary architecture
// is emulated by Rosetta.
func NativeArch() string { func NativeArch() string {
return runtime.GOARCH return runtime.GOARCH
} }

8
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
github.com/docker/distribution/registry/storage/cache/memory github.com/docker/distribution/registry/storage/cache/memory
github.com/docker/distribution/uuid github.com/docker/distribution/uuid
# github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible # github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible
## explicit ## explicit
github.com/docker/docker/api github.com/docker/docker/api
github.com/docker/docker/api/types github.com/docker/docker/api/types
@ -136,7 +136,7 @@ github.com/go-logr/logr/funcr
# github.com/go-logr/stdr v1.2.2 # github.com/go-logr/stdr v1.2.2
## explicit; go 1.16 ## explicit; go 1.16
github.com/go-logr/stdr github.com/go-logr/stdr
# github.com/go-viper/mapstructure/v2 v2.2.1 # github.com/go-viper/mapstructure/v2 v2.0.0
## explicit; go 1.18 ## explicit; go 1.18
github.com/go-viper/mapstructure/v2 github.com/go-viper/mapstructure/v2
github.com/go-viper/mapstructure/v2/internal/errors github.com/go-viper/mapstructure/v2/internal/errors
@ -205,7 +205,7 @@ github.com/moby/swarmkit/v2/api/defaults
github.com/moby/swarmkit/v2/api/genericresource github.com/moby/swarmkit/v2/api/genericresource
github.com/moby/swarmkit/v2/manager/raftselector github.com/moby/swarmkit/v2/manager/raftselector
github.com/moby/swarmkit/v2/protobuf/plugin github.com/moby/swarmkit/v2/protobuf/plugin
# github.com/moby/sys/capability v0.4.0 # github.com/moby/sys/capability v0.3.0
## explicit; go 1.21 ## explicit; go 1.21
github.com/moby/sys/capability github.com/moby/sys/capability
# github.com/moby/sys/sequential v0.6.0 # github.com/moby/sys/sequential v0.6.0
@ -293,7 +293,7 @@ github.com/theupdateframework/notary/tuf/data
github.com/theupdateframework/notary/tuf/signed github.com/theupdateframework/notary/tuf/signed
github.com/theupdateframework/notary/tuf/utils github.com/theupdateframework/notary/tuf/utils
github.com/theupdateframework/notary/tuf/validation github.com/theupdateframework/notary/tuf/validation
# github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 # github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d
## explicit; go 1.13 ## explicit; go 1.13
github.com/tonistiigi/go-rosetta github.com/tonistiigi/go-rosetta
# github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb # github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb