Compare commits

...

70 Commits

Author SHA1 Message Date
Sebastiaan van Stijn a829217d2f
Revert "Dockerfile: install libgcc instead of gcc"
This reverts commit df2a797b48.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-19 10:25:09 +02:00
Sebastiaan van Stijn c2ba0a01b2
scripts/build/plugins: don't -buildmode=pie without CGO enabled
The `.variables` sets `CGO_ENABLED=1` on arm; b0c41b78d8/scripts/build/.variables (L57-L68)
And if enabled, it sets `-buildmode=pie`; b0c41b78d8/scripts/build/.variables (L79-L88)

But that looks to be conflicting with the hard-coded `CGO_ENABLED=0` in
this script.

    > [build-plugins 1/1] RUN --mount=ro --mount=type=cache,target=/root/.cache     xx-go --wrap &&     TARGET=/out ./scripts/build/plugins e2e/cli-plugins/plugins/*:
    0.127 Building static docker-helloworld
    0.127 + CGO_ENABLED=0
    0.127 + GO111MODULE=auto
    0.127 + go build -o /out/plugins-linux-arm/docker-helloworld -tags ' osusergo' -ldflags ' -X "github.com/docker/cli/cli/version.GitCommit=5c123b1" -X "github.com/docker/cli/cli/version.BuildTime=2024-09-02T13:52:17Z" -X "github.com/docker/cli/cli/version.Version=pr-5387" -extldflags -static' -buildmode=pie github.com/docker/cli/cli-plugins/examples/helloworld
    0.135 -buildmode=pie requires external (cgo) linking, but cgo is not enabled

Remove `GO_BUILDMODE` from this script so that we don't try to build
with `-buildmode=pie`.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-19 10:25:05 +02:00
Sebastiaan van Stijn 25b5c27833
Dockerfile: install libgcc instead of gcc
The comment describes we need gcc for libgcc only, so we may
as well install that.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-19 10:22:16 +02:00
Sebastiaan van Stijn 0b68511f52
gha: add linux/arm/v5 to list of platforms
We include this in the moby/moby repo, but it looks like
we didn't for the CLI.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-19 10:22:13 +02:00
Sebastiaan van Stijn a5fb752ecf
Merge pull request #5445 from jsternberg/lowercase-windows-drive
command: change drive to lowercase for wsl path
2024-09-18 12:15:45 +02:00
Laura Brehm 4e64c59d64
Merge pull request #5446 from thaJeztah/codeql_updates
gha: update codeql workflow to go1.22.7
2024-09-18 11:04:32 +01:00
Jonathan A. Sternberg 3472bbc28a
command: change drive to lowercase for wsl path
On Windows, the drive casing doesn't matter outside of WSL. For WSL, the
drives are lowercase. When we're producing a WSL path, lowercase the
drive letter.

Co-authored-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Co-authored-by: Laura Brehm <laurabrehm@hey.com>

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-09-18 10:59:08 +01:00
Laura Brehm 649e564ee0
Merge pull request #5444 from jsternberg/handle-otel-errors
telemetry: pass otel errors to the otel handler for shutdown and force flush
2024-09-18 10:39:55 +01:00
Sebastiaan van Stijn e1213edcc6
gha: update codeql workflow to go1.22.7
commit d7d56599ca updated this
repository to go1.22, but the codeql action didn't specify a
patch version, and was missed.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-17 21:39:56 +02:00
Jonathan A. Sternberg b1956f5073
telemetry: pass otel errors to the otel handler for shutdown and force flush
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-09-17 10:47:04 -05:00
Sebastiaan van Stijn a4619f3676
Merge pull request #5435 from juliogarciape/docs-fix-container-run
Docs: Fix --rm=false flag in container_run.md
2024-09-16 15:17:06 +02:00
Sebastiaan van Stijn 539a92baca
Merge pull request #5441 from thaJeztah/bump_buildx_compose
Dockerfile: update buildx to v0.17.1, compose to v2.29.4
2024-09-16 15:15:09 +02:00
Sebastiaan van Stijn f7a513cff0
Dockerfile: update compose to v2.29.4
Update the compose cli plugin used in the dev-container

full diff: https://github.com/docker/compose/compare/v2.29.0...v2.29.4

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-16 15:03:15 +02:00
Sebastiaan van Stijn 42ce06aa5b
Dockerfile: update buildx to v0.17.1
Update the buildx cli plugin used in the dev-container

full diff: https://github.com/docker/buildx/compare/0.16.1...0.17.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-16 15:01:56 +02:00
Laura Brehm 7b630458bd
Merge pull request #5437 from thaJeztah/remove_deprecated_cors_headers
docs, man: dockerd: remove --api-cors-header (deprecated)
2024-09-16 13:42:01 +01:00
Sebastiaan van Stijn ccc87eb6ab
Merge pull request #5438 from thaJeztah/dockerd_logformat
docs, man: dockerd: add documentation for "--log-format" option
2024-09-16 13:44:19 +02:00
Sebastiaan van Stijn 4f78ffaa03
Merge pull request #5436 from thaJeztah/update_dockerd_docs
docs: add documentation for dockerd --feature flag
2024-09-16 13:43:57 +02:00
Sebastiaan van Stijn baceb4b158
docs: dockerd: add documentation for --log-format option
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-16 13:23:13 +02:00
Sebastiaan van Stijn a42ca1148d
docs/reference: dockerd: add docs for --feature option
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-16 13:20:48 +02:00
Sebastiaan van Stijn 9ae514fdc7
man: dockerd: add description for --log-format option
This option was added in a08abec9f8d59eaa44c375900e254384a68c5a31,
as part of Docker v25.0, but did not update the docs and manpage.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-16 12:46:30 +02:00
Sebastiaan van Stijn 1a0e32099a
docs: dockerd: remove --api-cors-header (deprecated)
Updates 9d9bb19f01

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-16 12:20:54 +02:00
Sebastiaan van Stijn 9bfd0e1a40
man: remove docs for deprecated --api-cors-header
It was deprecated in 27.0x through 7ea9acc97f4c884ecdaebd06ed0353b28263d118,
and removed in ae96ce866f4b3dc09dc4eab019d7725a63623d94.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-16 12:15:24 +02:00
Sebastiaan van Stijn a357db0aba
man: dockerd: value is optional for --feature flag
The --feature flag allows the boolean value to be omitted.
If only a name is provided, the default is "true".

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-16 11:22:21 +02:00
Sebastiaan van Stijn fb056d2ceb
man: fix duplicate word in --feature flag description
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-16 11:22:15 +02:00
Sebastiaan van Stijn 610f9157f5
man: update dockerd man-page to include --feature flag
commit f13c08246d93dd5aae200d5881a3a374e6cac876 introduced
this flag, but did not yet update the manpage.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-16 11:22:08 +02:00
Julio Cesar Garcia 605c9bf160 docs: Fix --rm=false flag in container_run.md
Signed-off-by: Julio Cesar Garcia <juliogarciamelgarejo@gmail.com>
2024-09-13 18:45:26 -05:00
Sebastiaan van Stijn a18c896928
Merge pull request #5424 from jsternberg/wsl-socket-path
command: check for wsl mount path on windows
2024-09-13 00:33:13 +02:00
Sebastiaan van Stijn b0333da63c
Merge pull request #5427 from thaJeztah/bump_docker_deps
vendor: update various dependencies
2024-09-12 19:07:02 +02:00
Sebastiaan van Stijn dccb8bfa5d
vendor: google.golang.org/grpc v1.62.0
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-12 18:38:40 +02:00
Sebastiaan van Stijn 8cdf90cd93
vendor: tags.cncf.io/container-device-interface v0.8.0
Breaking change: The .ToOCI() functions in the specs-go package have been
removed. This removes the dependency on the OCI runtime specification from
the CDI specification definition itself.

What's Changed

- Add workflow to mark prs and issues as stale
- Remove the ToOCI functions from the specs-go package
- docs: add a pointer to community meetings in our docs.
- Bump spec version to v0.8.0
- Update spec version in README

Full diff: https://github.com/cncf-tags/container-device-interface/compare/v0.7.2...v0.8.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-12 18:36:26 +02:00
Sebastiaan van Stijn a5f15bee7a
vendor: golang.org/x/net v0.28.0
full diff: https://github.com/golang/net/compare/v0.25.0...v0.28.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-12 18:33:40 +02:00
Sebastiaan van Stijn b93fc39639
vendor: golang.org/x/crypto v0.26.0
full diff: https://github.com/golang/crypto/compare/v0.23.0...v0.26.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-12 18:32:05 +02:00
Sebastiaan van Stijn 3a63df265f
vendor: golang.org/x/text v0.17.0
full diff: https://github.com/golang/text/compare/v0.15.0...v0.17.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-12 18:31:04 +02:00
Sebastiaan van Stijn c6e5341934
vendor: golang.org/x/term v0.23.0
full diff: https://github.com/golang/term/compare/v0.20.0...v0.23.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-12 18:29:52 +02:00
Sebastiaan van Stijn 5f9fe33b6b
vendor: golang.org/x/time v0.6.0
full diff: https://github.com/golang/time/compare/v0.3.0...v0.6.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-12 18:26:45 +02:00
Sebastiaan van Stijn 7074e5011f
vendor: golang.org/x/sync v0.8.0
full diff: https://github.com/golang/sync/compare/v0.7.0...v0.8.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-12 18:24:38 +02:00
Sebastiaan van Stijn 958fff82f1
vendor: golang.org/x/sys v0.24.0
full diff: https://github.com/golang/sys/compare/v0.22.0...v0.24.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-12 18:24:02 +02:00
Sebastiaan van Stijn fb264ffc08
vendor: dario.cat/mergo v1.0.1
- fix: overwriteWithEmptyValue is forced to true when merging an object
  involving maps
- fix: WithoutDereference should respect non-nil struct pointers

full diff: https://github.com/darccio/mergo/compare/v1.0.0...v1.0.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-12 18:18:47 +02:00
Jonathan A. Sternberg 38c3fef1a8
command: check for wsl mount path on windows
This checks for the equivalent WSL mount path on windows. WSL will mount
the windows drives at `/mnt/c` (or whichever drive is being used).

This is done by parsing a UNC path with forward slashes from the unix
socket URL.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-09-12 11:14:43 -05:00
Laura Brehm 986baf22c7
Merge pull request #5425 from zeghong/remove-dup-linter
chore: remove duplicated `govet` linter config
2024-09-11 11:35:50 +01:00
Li Zeghong 5b81f0dcb0 chore: remove duplicated `govet` linter config
Signed-off-by: Li Zeghong <zeghong@hotmail.com>
2024-09-11 17:55:43 +08:00
Sebastiaan van Stijn 6965f40090
Merge pull request #5422 from thaJeztah/info_no_expected_version
info: stop printing "Expected" commits
2024-09-10 19:43:51 +02:00
Sebastiaan van Stijn 88ca4e958f
info: stop printing "Expected" commits
The `Commit` type was introduced in 2790ac68b3,
to assist triaging issues that were reported with an incorrect version of
runc or containerd. At the time, both `runc` and `containerd` were not yet
stable, and had to be built from a specific commit to guarantee compatibility.

We encountered various situations where unexpected (and incompatible) versions
of those binaries were packaged, resulting in hard to trace bug-reports.
For those situations, a "expected" version was set at compile time, to
indicate if the version installed was different from the expected version;

    docker info
    ...
    runc version: a592beb5bc4c4092b1b1bac971afed27687340c5 (expected: 69663f0bd4b60df09991c08812a60108003fa340)

Both `runc` and `containerd` are stable now, and docker 19.03 and up set the
expected version to the actual version since c65f0bd13c
and 23.0 did the same for the `init` binary b585c64e2b,
to prevent the CLI from reporting "unexpected version".

In short; the `Expected` fields no longer serves a real purpose, so we should
no longer print it.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-10 13:49:12 +02:00
Sebastiaan van Stijn a464a63d33
Merge pull request #5420 from laurazard/fix-panic-volume-update
volume/update: require 1 argument/fix panic
2024-09-09 20:46:30 +02:00
Laura Brehm daea277ee8
volume/update: require 1 argument/fix panic
This command was declaring that it requires at least 1 argument, when it
needs exactly 1 argument. This was causing the CLI to panic when the
command was invoked with no argument:

`docker volume update`

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-09-09 13:40:03 +01:00
Alano Terblanche 6372ec9c75
Merge pull request #5415 from lentil32/master
fix: docstring for cli/command: `ContainerFormat.CreatedAt`
2024-09-09 12:19:53 +02:00
Sebastiaan van Stijn 21ee2685e3
Merge pull request #5403 from dvdksn/docs-update-titles
docs: rename plugins index file and add linkTitle
2024-09-09 11:04:09 +02:00
David Karlsson 0fcaffb7e4 chore: fix style/lint issues in deprecated.md
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-09-09 10:53:38 +02:00
Alano Terblanche 2230089371
Merge pull request #5381 from Benehiko/lf-exclude-binary
fix: gitattributes enforcing line endings
2024-09-09 08:51:54 +02:00
lentil32 0b9d58245a
cli/command: fix docstring for ContainerFormat.CreatedAt
Signed-off-by: lentil32 <lentil32@icloud.com>
2024-09-08 15:47:21 +09:00
Sebastiaan van Stijn 6b741602c8
Merge pull request #5410 from vvoland/update-go
update to go1.22.7
2024-09-06 10:27:26 +02:00
Alano Terblanche 4a6ab2b37d
fix: binary file line endings
Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com>
2024-09-06 10:23:23 +02:00
Paweł Gronowski 3bf39d25a0
update to go1.22.7
- https://github.com/golang/go/issues?q=milestone%3AGo1.22.7+label%3ACherryPickApproved
- full diff: https://github.com/golang/go/compare/go1.22.6...go1.22.7

These minor releases include 3 security fixes following the security policy:

- go/parser: stack exhaustion in all Parse* functions

    Calling any of the Parse functions on Go source code which contains deeply nested literals can cause a panic due to stack exhaustion.

    This is CVE-2024-34155 and Go issue https://go.dev/issue/69138.

- encoding/gob: stack exhaustion in Decoder.Decode

    Calling Decoder.Decode on a message which contains deeply nested structures can cause a panic due to stack exhaustion.

    This is a follow-up to CVE-2022-30635.

    Thanks to Md Sakib Anwar of The Ohio State University (anwar.40@osu.edu) for reporting this issue.

    This is CVE-2024-34156 and Go issue https://go.dev/issue/69139.

- go/build/constraint: stack exhaustion in Parse

    Calling Parse on a "// +build" build tag line with deeply nested expressions can cause a panic due to stack exhaustion.

    This is CVE-2024-34158 and Go issue https://go.dev/issue/69141.

View the release notes for more information:
https://go.dev/doc/devel/release#go1.23.1

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2024-09-05 17:51:27 +02:00
Laura Brehm 2b6d2d98d8
Merge pull request #5407 from thaJeztah/mod_tidy
vendor.mod: put github.com/pkg/browser in the right group
2024-09-05 13:47:37 +01:00
Sebastiaan van Stijn 1b8180a405
vendor.mod: put github.com/pkg/browser in the right group
commit fcfdd7b91f introduced github.com/pkg/browser
as a direct dependency, but it ended up in the group for indirect dependencies.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-05 14:36:51 +02:00
David Karlsson 5ca40e0a35 docs: add front matter title to deprecated.md
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-09-04 13:48:37 +02:00
David Karlsson 071f6f9391 docs: rename plugins index file and add linkTitle
We publish this page on docs.docker.com, and hugo expects index pages
for sections to be named _index.md. We currently rename the page when we
mount it to the docs repo but might as well change the filename in the
source.

Also adds a linkTitle to the page, which is a shorter title that will be
used in the sidebar navigation and breadcrumbs.

Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-09-04 13:48:37 +02:00
Sebastiaan van Stijn f75abad8a1
Merge pull request #5401 from laurazard/login-non-tty-standardize
login: handle non-tty scenario consistently
2024-09-03 16:36:14 +02:00
Laura Brehm bbb6e7643d
login: handle non-tty scenario consistently
Running `docker login` in a non-interactive environment sometimes errors
out if no username/pwd is provided. This handling is somewhat
inconsistent – this commit addresses that.

Before:
| `--username` | `--password` | Result                                                             |
|:------------:|:------------:| ------------------------------------------------------------------ |
|            |            |                                                                  |
|            |            | `Error: Cannot perform an interactive login from a non TTY device` |
|            |            | `Error: Cannot perform an interactive login from a non TTY device` |
|            |            | hangs                                                              |

After:
| `--username` | `--password` | Result                                                             |
|:------------:|:------------:| ------------------------------------------------------------------ |
|            |            |                                                                  |
|            |            | `Error: Cannot perform an interactive login from a non TTY device` |
|            |            | `Error: Cannot perform an interactive login from a non TTY device` |
|            |            | `Error: Cannot perform an interactive login from a non TTY device` |

It's worth calling out a separate scenario – if there are previous,
valid credentials, then running `docker login` with no username or
password provided will use the previously stored credentials, and not
error out.

```console
cat ~/.docker/config.json
{
        "auths": {
                "https://index.docker.io/v1/": {
                        "auth": "xxxxxxxxxxx"
                }
        }
}
⭑ docker login 0>/dev/null
Authenticating with existing credentials...

Login Succeeded
```

This commit also applies the same non-interactive handling logic to the
new web-based login flow, which means that now, if there are no prior
credentials stored and a user runs `docker login`, instead of initiating
the new web-based login flow, an error is returned.

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-09-03 14:26:11 +01:00
Sebastiaan van Stijn 2dd127a1ff
Merge pull request #5387 from thaJeztah/update_go_1.22
update to go1.22.6
2024-09-03 13:25:16 +02:00
Sebastiaan van Stijn 51f320ff62
Merge pull request #5376 from laurazard/fix-oauth-login-timer
oauth/api: drain timer channel on each iteration
2024-09-03 13:14:54 +02:00
Laura Brehm 60d0450287
oauth/api: drain timer channel on each iteration
Previously, if while polling for oauth device-code login results a user
suspended the process (such as with CTRL-Z) and then restored it with
`fg`, an error might occur in the form of:

```
failed waiting for authentication: You are polling faster than the specified interval of 5 seconds.
```

This is due to our use of a `time.Ticker` here - if no receiver drains
the ticker channel (and timers/tickers use a buffered channel behind the
scenes), more than one tick will pile up, causing the program to "tick"
twice, in fast succession, after it is resumed.

The new implementation replaces the `time.Ticker` with a `time.Timer`
(`time.Ticker` is just a nice wrapper) and introduces a helper function
`resetTimer` to ensure that before every `select`, the timer is stopped
and it's channel is drained.

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-09-03 11:31:03 +01:00
Sebastiaan van Stijn d7d56599ca
update to go1.22.6
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-03 12:29:03 +02:00
Sebastiaan van Stijn 623af469bb
Merge pull request #5393 from thaJeztah/fix_plugins_CGO_ENABLED
scripts/build/plugins: don't override CGO_ENABLED set by .variables
2024-09-03 12:28:21 +02:00
Sebastiaan van Stijn e3676d233e
Merge pull request #5386 from dvdksn/docker-login-docs-touchup
docs: update docker login reference
2024-09-03 12:15:08 +02:00
Sebastiaan van Stijn 9e29967960
scripts/build/plugins: don't override CGO_ENABLED set by .variables
The `.variables` sets `CGO_ENABLED=1` on arm; b0c41b78d8/scripts/build/.variables (L57-L68)
And if enabled, it sets `-buildmode=pie`; b0c41b78d8/scripts/build/.variables (L79-L88)

But that looks to be conflicting with the hardcoded `CGO_ENABLED=0` in
this script, which causes the build to fail on go1.22;

    > [build-plugins 1/1] RUN --mount=ro --mount=type=cache,target=/root/.cache     xx-go --wrap &&     TARGET=/out ./scripts/build/plugins e2e/cli-plugins/plugins/*:
    0.127 Building static docker-helloworld
    0.127 + CGO_ENABLED=0
    0.127 + GO111MODULE=auto
    0.127 + go build -o /out/plugins-linux-arm/docker-helloworld -tags ' osusergo' -ldflags ' -X "github.com/docker/cli/cli/version.GitCommit=5c123b1" -X "github.com/docker/cli/cli/version.BuildTime=2024-09-02T13:52:17Z" -X "github.com/docker/cli/cli/version.Version=pr-5387" -extldflags -static' -buildmode=pie github.com/docker/cli/cli-plugins/examples/helloworld
    0.135 -buildmode=pie requires external (cgo) linking, but cgo is not enabled

This patch sets the CGO_ENABLED variable before sourcing `.variables`,
so that other variables which are conditionally set are handled correctly.

Before this PR:

    #18 [build-plugins 1/1] RUN --mount=ro --mount=type=cache,target=/root/.cache     xx-go --wrap &&     TARGET=/out ./scripts/build/plugins e2e/cli-plugins/plugins/*
    #18 0.123 Building static docker-helloworld
    #18 0.124 + CGO_ENABLED=0
    #18 0.124 + GO111MODULE=auto
    #18 0.124 + go build -o /out/plugins-linux-arm/docker-helloworld -tags ' osusergo' -ldflags ' -X "github.com/docker/cli/cli/version.GitCommit=c8c402e" -X "github.com/docker/cli/cli/version.BuildTime=2024-09-03T08:28:25Z" -X "github.com/docker/cli/cli/version.Version=pr-5381" -extldflags -static' -buildmode=pie github.com/docker/cli/cli-plugins/examples/helloworld
    ....

With this PR:

    #18 [build-plugins 1/1] RUN --mount=ro --mount=type=cache,target=/root/.cache     xx-go --wrap &&     TARGET=/out ./scripts/build/plugins e2e/cli-plugins/plugins/*
    #18 0.110 Building static docker-helloworld
    #18 0.110 + GO111MODULE=auto
    #18 0.110 + go build -o /out/plugins-linux-arm/docker-helloworld -tags '' -ldflags ' -X "github.com/docker/cli/cli/version.GitCommit=050d9d6" -X "github.com/docker/cli/cli/version.BuildTime=2024-09-03T09:19:05Z" -X "github.com/docker/cli/cli/version.Version=pr-5387"' github.com/docker/cli/cli-plugins/examples/helloworld
    ....

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-03 11:49:43 +02:00
David Karlsson 81744d7aa8 copynit: s/WEB BASED/WEB-BASED/
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-09-03 11:39:43 +02:00
David Karlsson 2f206fff3c docs: update docker login reference
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
2024-09-03 11:38:05 +02:00
Paweł Gronowski 092b5f0fcb
Merge pull request #5389 from thaJeztah/bump_xx
Dockerfile: update xx to v1.5.0
2024-09-02 18:55:05 +00:00
Sebastiaan van Stijn 1e6cbbc3f1
Dockerfile: update xx to v1.5.0
full diff: https://github.com/tonistiigi/xx/compare/v1.4.0...v1.5.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-09-02 16:48:29 +02:00
161 changed files with 2141 additions and 2801 deletions

13
.gitattributes vendored
View File

@ -1,5 +1,14 @@
* text=auto eol=lf
* text=auto
Dockerfile* linguist-language=Dockerfile
vendor.mod linguist-language=Go-Module
vendor.sum linguist-language=Go-Checksums
*.bat text eol=crlf
*.go -text diff=golang
# scripts directory contains shell scripts
# without extensions, so we need to force
scripts/** text=auto eol=lf
# shell scripts should always have LF
*.sh text eol=lf

View File

@ -67,7 +67,7 @@ jobs:
name: Update Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
go-version: 1.22.7
-
name: Initialize CodeQL
uses: github/codeql-action/init@v3

View File

@ -68,7 +68,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.21.13
go-version: 1.22.7
-
name: Test
run: |

View File

@ -35,7 +35,6 @@ linters:
- unparam
- unused
- usestdlibvars
- govet
- wastedassign
disable:

View File

@ -4,12 +4,12 @@ ARG BASE_VARIANT=alpine
ARG ALPINE_VERSION=3.20
ARG BASE_DEBIAN_DISTRO=bookworm
ARG GO_VERSION=1.21.13
ARG XX_VERSION=1.4.0
ARG GO_VERSION=1.22.7
ARG XX_VERSION=1.5.0
ARG GOVERSIONINFO_VERSION=v1.3.0
ARG GOTESTSUM_VERSION=v1.10.0
ARG BUILDX_VERSION=0.16.1
ARG COMPOSE_VERSION=v2.29.0
ARG BUILDX_VERSION=0.17.1
ARG COMPOSE_VERSION=v2.29.4
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx

View File

@ -193,7 +193,9 @@ func (c *ContainerContext) Command() string {
return strconv.Quote(command)
}
// CreatedAt returns the "Created" date/time of the container as a unix timestamp.
// CreatedAt returns the formatted string representing the container's creation date/time.
// The format may include nanoseconds if present.
// e.g. "2006-01-02 15:04:05.999999999 -0700 MST" or "2006-01-02 15:04:05 -0700 MST"
func (c *ContainerContext) CreatedAt() string {
return time.Unix(c.c.Created, 0).String()
}

View File

@ -124,17 +124,6 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
cli.SetIn(streams.NewIn(os.Stdin))
}
// Some links documenting this:
// - https://code.google.com/archive/p/mintty/issues/56
// - https://github.com/docker/docker/issues/15272
// - https://mintty.github.io/ (compatibility)
// Linux will hit this if you attempt `cat | docker login`, and Windows
// will hit this if you attempt docker login from mintty where stdin
// is a pipe, not a character based console.
if argPassword == "" && !cli.In().IsTerminal() {
return authConfig, errors.Errorf("Error: Cannot perform an interactive login from a non TTY device")
}
isDefaultRegistry := serverAddress == registry.IndexServer
defaultUsername = strings.TrimSpace(defaultUsername)

View File

@ -34,8 +34,8 @@ func NewLoginCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "login [OPTIONS] [SERVER]",
Short: "Log in to a registry",
Long: "Log in to a registry.\nIf no server is specified, the default is defined by the daemon.",
Short: "Authenticate to a registry",
Long: "Authenticate to a registry.\nDefaults to Docker Hub if no server is specified.",
Args: cli.RequiresMaxArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
@ -155,6 +155,17 @@ func isOauthLoginDisabled() bool {
}
func loginUser(ctx context.Context, dockerCli command.Cli, opts loginOptions, defaultUsername, serverAddress string) (*registrytypes.AuthenticateOKBody, error) {
// Some links documenting this:
// - https://code.google.com/archive/p/mintty/issues/56
// - https://github.com/docker/docker/issues/15272
// - https://mintty.github.io/ (compatibility)
// Linux will hit this if you attempt `cat | docker login`, and Windows
// will hit this if you attempt docker login from mintty where stdin
// is a pipe, not a character based console.
if (opts.user == "" || opts.password == "") && !dockerCli.In().IsTerminal() {
return nil, errors.Errorf("Error: Cannot perform an interactive login from a non TTY device")
}
// If we're logging into the index server and the user didn't provide a username or password, use the device flow
if serverAddress == registry.IndexServer && opts.user == "" && opts.password == "" && !isOauthLoginDisabled() {
response, err := loginWithDeviceCodeFlow(ctx, dockerCli)

View File

@ -313,6 +313,145 @@ func TestRunLogin(t *testing.T) {
}
}
func TestLoginNonInteractive(t *testing.T) {
t.Run("no prior credentials", func(t *testing.T) {
testCases := []struct {
doc string
username bool
password bool
expectedErr string
}{
{
doc: "success - w/ user w/ password",
username: true,
password: true,
},
{
doc: "error - w/o user w/o pass ",
username: false,
password: false,
expectedErr: "Error: Cannot perform an interactive login from a non TTY device",
},
{
doc: "error - w/ user w/o pass",
username: true,
password: false,
expectedErr: "Error: Cannot perform an interactive login from a non TTY device",
},
{
doc: "error - w/o user w/ pass",
username: false,
password: true,
expectedErr: "Error: Cannot perform an interactive login from a non TTY device",
},
}
// "" meaning default registry
registries := []string{"", "my-registry.com"}
for _, registry := range registries {
for _, tc := range testCases {
t.Run(tc.doc, func(t *testing.T) {
tmpFile := fs.NewFile(t, "test-run-login")
defer tmpFile.Remove()
cli := test.NewFakeCli(&fakeClient{})
configfile := cli.ConfigFile()
configfile.Filename = tmpFile.Path()
options := loginOptions{
serverAddress: registry,
}
if tc.username {
options.user = "my-username"
}
if tc.password {
options.password = "my-password"
}
loginErr := runLogin(context.Background(), cli, options)
if tc.expectedErr != "" {
assert.Error(t, loginErr, tc.expectedErr)
return
}
assert.NilError(t, loginErr)
})
}
}
})
t.Run("w/ prior credentials", func(t *testing.T) {
testCases := []struct {
doc string
username bool
password bool
expectedErr string
}{
{
doc: "success - w/ user w/ password",
username: true,
password: true,
},
{
doc: "success - w/o user w/o pass ",
username: false,
password: false,
},
{
doc: "error - w/ user w/o pass",
username: true,
password: false,
expectedErr: "Error: Cannot perform an interactive login from a non TTY device",
},
{
doc: "error - w/o user w/ pass",
username: false,
password: true,
expectedErr: "Error: Cannot perform an interactive login from a non TTY device",
},
}
// "" meaning default registry
registries := []string{"", "my-registry.com"}
for _, registry := range registries {
for _, tc := range testCases {
t.Run(tc.doc, func(t *testing.T) {
tmpFile := fs.NewFile(t, "test-run-login")
defer tmpFile.Remove()
cli := test.NewFakeCli(&fakeClient{})
configfile := cli.ConfigFile()
configfile.Filename = tmpFile.Path()
serverAddress := registry
if serverAddress == "" {
serverAddress = "https://index.docker.io/v1/"
}
assert.NilError(t, configfile.GetCredentialsStore(serverAddress).Store(configtypes.AuthConfig{
Username: "my-username",
Password: "my-password",
ServerAddress: serverAddress,
}))
options := loginOptions{
serverAddress: registry,
}
if tc.username {
options.user = "my-username"
}
if tc.password {
options.password = "my-password"
}
loginErr := runLogin(context.Background(), cli, options)
if tc.expectedErr != "" {
assert.Error(t, loginErr, tc.expectedErr)
return
}
assert.NilError(t, loginErr)
})
}
}
})
}
func TestLoginTermination(t *testing.T) {
p, tty, err := pty.Open()
assert.NilError(t, err)

View File

@ -273,21 +273,9 @@ func prettyPrintServerInfo(streams command.Streams, info *dockerInfo) []error {
if info.OSType == "linux" {
fprintln(output, " Init Binary:", info.InitBinary)
for _, ci := range []struct {
Name string
Commit system.Commit
}{
{"containerd", info.ContainerdCommit},
{"runc", info.RuncCommit},
{"init", info.InitCommit},
} {
fprintf(output, " %s version: %s", ci.Name, ci.Commit.ID)
if ci.Commit.ID != ci.Commit.Expected {
fprintf(output, " (expected: %s)", ci.Commit.Expected)
}
fprintln(output)
}
fprintln(output, " containerd version:", info.ContainerdCommit.ID)
fprintln(output, " runc version:", info.RuncCommit.ID)
fprintln(output, " init version:", info.InitCommit.ID)
if len(info.SecurityOptions) != 0 {
if kvs, err := system.DecodeSecurityOptions(info.SecurityOptions); err != nil {
errs = append(errs, err)

View File

@ -5,9 +5,14 @@ package command
import (
"context"
"fmt"
"io/fs"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"unicode"
"github.com/pkg/errors"
"go.opentelemetry.io/otel"
@ -77,14 +82,7 @@ func dockerExporterOTLPEndpoint(cli Cli) (endpoint string, secure bool) {
switch u.Scheme {
case "unix":
// Unix sockets are a bit weird. OTEL seems to imply they
// can be used as an environment variable and are handled properly,
// but they don't seem to be as the behavior of the environment variable
// is to strip the scheme from the endpoint, but the underlying implementation
// needs the scheme to use the correct resolver.
//
// We'll just handle this in a special way and add the unix:// back to the endpoint.
endpoint = "unix://" + path.Join(u.Host, u.Path)
endpoint = unixSocketEndpoint(u)
case "https":
secure = true
fallthrough
@ -135,3 +133,109 @@ func dockerMetricExporter(ctx context.Context, cli Cli) []sdkmetric.Option {
}
return []sdkmetric.Option{sdkmetric.WithReader(newCLIReader(exp))}
}
// unixSocketEndpoint converts the unix scheme from URL to
// an OTEL endpoint that can be used with the OTLP exporter.
//
// The OTLP exporter handles unix sockets in a strange way.
// It seems to imply they can be used as an environment variable
// and are handled properly, but they don't seem to be as the behavior
// of the environment variable is to strip the scheme from the endpoint
// while the underlying implementation needs the scheme to use the
// correct resolver.
func unixSocketEndpoint(u *url.URL) string {
// GRPC does not allow host to be used.
socketPath := u.Path
// If we are on windows and we have an absolute path
// that references a letter drive, check to see if the
// WSL equivalent path exists and we should use that instead.
if isWsl() {
if p := wslSocketPath(socketPath, os.DirFS("/")); p != "" {
socketPath = p
}
}
// Enforce that we are using forward slashes.
return "unix://" + filepath.ToSlash(socketPath)
}
// wslSocketPath will convert the referenced URL to a WSL-compatible
// path and check if that path exists. If the path exists, it will
// be returned.
func wslSocketPath(s string, f fs.FS) string {
if p := toWslPath(s); p != "" {
if _, err := stat(p, f); err == nil {
return "/" + p
}
}
return ""
}
// toWslPath converts the referenced URL to a WSL-compatible
// path if this looks like a Windows absolute path.
//
// If no drive is in the URL, defaults to the C drive.
func toWslPath(s string) string {
drive, p, ok := parseUNCPath(s)
if !ok {
return ""
}
return fmt.Sprintf("mnt/%s%s", strings.ToLower(drive), p)
}
func parseUNCPath(s string) (drive, p string, ok bool) {
// UNC paths use backslashes but we're using forward slashes
// so also enforce that here.
//
// In reality, this should have been enforced much earlier
// than here since backslashes aren't allowed in URLs, but
// we're going to code defensively here.
s = filepath.ToSlash(s)
const uncPrefix = "//./"
if !strings.HasPrefix(s, uncPrefix) {
// Not a UNC path.
return "", "", false
}
s = s[len(uncPrefix):]
parts := strings.SplitN(s, "/", 2)
if len(parts) != 2 {
// Not enough components.
return "", "", false
}
drive, ok = splitWindowsDrive(parts[0])
if !ok {
// Not a windows drive.
return "", "", false
}
return drive, "/" + parts[1], true
}
// splitWindowsDrive checks if the string references a windows
// drive (such as c:) and returns the drive letter if it is.
func splitWindowsDrive(s string) (string, bool) {
if b := []rune(s); len(b) == 2 && unicode.IsLetter(b[0]) && b[1] == ':' {
return string(b[0]), true
}
return "", false
}
func stat(p string, f fs.FS) (fs.FileInfo, error) {
if f, ok := f.(fs.StatFS); ok {
return f.Stat(p)
}
file, err := f.Open(p)
if err != nil {
return nil, err
}
defer file.Close()
return file.Stat()
}
func isWsl() bool {
return os.Getenv("WSL_DISTRO_NAME") != ""
}

View File

@ -0,0 +1,57 @@
package command
import (
"io/fs"
"net/url"
"testing"
"testing/fstest"
"gotest.tools/v3/assert"
)
func TestWslSocketPath(t *testing.T) {
testCases := []struct {
doc string
fs fs.FS
url string
expected string
}{
{
doc: "filesystem where WSL path does not exist",
fs: fstest.MapFS{
"my/file/path": {},
},
url: "unix:////./c:/my/file/path",
expected: "",
},
{
doc: "filesystem where WSL path exists",
fs: fstest.MapFS{
"mnt/c/my/file/path": {},
},
url: "unix:////./c:/my/file/path",
expected: "/mnt/c/my/file/path",
},
{
doc: "filesystem where WSL path exists uppercase URL",
fs: fstest.MapFS{
"mnt/c/my/file/path": {},
},
url: "unix:////./C:/my/file/path",
expected: "/mnt/c/my/file/path",
},
}
for _, tc := range testCases {
t.Run(tc.doc, func(t *testing.T) {
u, err := url.Parse(tc.url)
assert.NilError(t, err)
// Ensure host is empty.
assert.Equal(t, u.Host, "")
result := wslSocketPath(u.Path, tc.fs)
assert.Equal(t, result, tc.expected)
})
}
}

View File

@ -9,6 +9,7 @@ import (
"github.com/docker/cli/cli/version"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
)
@ -94,7 +95,9 @@ func startCobraCommandTimer(mp metric.MeterProvider, attrs []attribute.KeyValue)
metric.WithAttributes(cmdStatusAttrs...),
)
if mp, ok := mp.(MeterProvider); ok {
mp.ForceFlush(ctx)
if err := mp.ForceFlush(ctx); err != nil {
otel.Handle(err)
}
}
}
}

View File

@ -18,7 +18,7 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
cmd := &cobra.Command{
Use: "update [OPTIONS] [VOLUME]",
Short: "Update a volume (cluster volumes only)",
Args: cli.RequiresMaxArgs(1),
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return runUpdate(cmd.Context(), dockerCli, args[0], availability, cmd.Flags())
},

View File

@ -0,0 +1,22 @@
package volume
import (
"io"
"testing"
"github.com/docker/cli/internal/test"
"gotest.tools/v3/assert"
)
func TestUpdateCmd(t *testing.T) {
cmd := newUpdateCommand(
test.NewFakeCli(&fakeClient{}),
)
cmd.SetArgs([]string{})
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
err := cmd.Execute()
assert.ErrorContains(t, err, "requires 1 argument")
}

View File

@ -96,18 +96,32 @@ func tryDecodeOAuthError(resp *http.Response) error {
// authenticated or we have reached the time limit for authenticating (based on
// the response from GetDeviceCode).
func (a API) WaitForDeviceToken(ctx context.Context, state State) (TokenResponse, error) {
ticker := time.NewTicker(state.IntervalDuration())
// Ticker for polling tenant for login based on the interval
// specified by the tenant response.
ticker := time.NewTimer(state.IntervalDuration())
defer ticker.Stop()
timeout := time.After(state.ExpiryDuration())
// The tenant tells us for as long as we can poll it for credentials
// while the user logs in through their browser. Timeout if we don't get
// credentials within this period.
timeout := time.NewTimer(state.ExpiryDuration())
defer timeout.Stop()
for {
resetTimer(ticker, state.IntervalDuration())
select {
case <-ctx.Done():
// user canceled login
return TokenResponse{}, ctx.Err()
case <-ticker.C:
// tick, check for user login
res, err := a.getDeviceToken(ctx, state)
if err != nil {
return res, err
if errors.Is(err, context.Canceled) {
// if the caller canceled the context, continue
// and let the select hit the ctx.Done() branch
continue
}
return TokenResponse{}, err
}
if res.Error != nil {
@ -119,14 +133,33 @@ func (a API) WaitForDeviceToken(ctx context.Context, state State) (TokenResponse
}
return res, nil
case <-timeout:
case <-timeout.C:
// login timed out
return TokenResponse{}, ErrTimeout
}
}
}
// resetTimer is a helper function thatstops, drains and resets the timer.
// This is necessary in go versions <1.23, since the timer isn't stopped +
// the timer's channel isn't drained on timer.Reset.
// See: https://go-review.googlesource.com/c/go/+/568341
// FIXME: remove/simplify this after we update to go1.23
func resetTimer(t *time.Timer, d time.Duration) {
if !t.Stop() {
select {
case <-t.C:
default:
}
}
t.Reset(d)
}
// getToken calls the token endpoint of Auth0 and returns the response.
func (a API) getDeviceToken(ctx context.Context, state State) (TokenResponse, error) {
ctx, cancel := context.WithTimeout(ctx, 1*time.Minute)
defer cancel()
data := url.Values{
"client_id": {a.ClientID},
"grant_type": {"urn:ietf:params:oauth:grant-type:device_code"},

View File

@ -198,7 +198,7 @@ func TestWaitForDeviceToken(t *testing.T) {
state := State{
DeviceCode: "aDeviceCode",
UserCode: "aUserCode",
Interval: 1,
Interval: 5,
ExpiresIn: 1,
}

View File

@ -92,7 +92,7 @@ func (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.Aut
return nil, ErrDeviceLoginStartFail
}
_, _ = fmt.Fprintln(w, aec.Bold.Apply("\nUSING WEB BASED LOGIN"))
_, _ = fmt.Fprintln(w, aec.Bold.Apply("\nUSING WEB-BASED LOGIN"))
_, _ = fmt.Fprintln(w, "To sign in with credentials on the command line, use 'docker login -u <username>'")
_, _ = fmt.Fprintf(w, "\nYour one-time device confirmation code is: "+aec.Bold.Apply("%s\n"), state.UserCode)
_, _ = fmt.Fprintf(w, aec.Bold.Apply("Press ENTER")+" to open your browser or submit your device code here: "+aec.Underline.Apply("%s\n"), strings.Split(state.VerificationURI, "?")[0])

View File

@ -358,7 +358,9 @@ func runDocker(ctx context.Context, dockerCli *command.DockerCli) error {
mp := dockerCli.MeterProvider()
if mp, ok := mp.(command.MeterProvider); ok {
defer mp.Shutdown(ctx)
if err := mp.Shutdown(ctx); err != nil {
otel.Handle(err)
}
} else {
fmt.Fprint(dockerCli.Err(), "Warning: Unexpected OTEL error, metrics may not be flushed")
}

View File

@ -1,5 +1,5 @@
variable "GO_VERSION" {
default = "1.21.13"
default = "1.22.7"
}
variable "VERSION" {
default = ""
@ -31,6 +31,7 @@ target "_platforms" {
"darwin/amd64",
"darwin/arm64",
"linux/amd64",
"linux/arm/v5",
"linux/arm/v6",
"linux/arm/v7",
"linux/arm64",
@ -183,6 +184,7 @@ target "bin-image-cross" {
"darwin/amd64",
"darwin/arm64",
"linux/amd64",
"linux/arm/v5",
"linux/arm/v6",
"linux/arm/v7",
"linux/arm64",

View File

@ -1,9 +1,9 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.21.13
ARG GO_VERSION=1.22.7
ARG ALPINE_VERSION=3.20
ARG BUILDX_VERSION=0.16.1
ARG BUILDX_VERSION=0.17.1
FROM docker/buildx-bin:${BUILDX_VERSION} AS buildx
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS golang

View File

@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.21.13
ARG GO_VERSION=1.22.7
ARG ALPINE_VERSION=3.20
ARG GOLANGCI_LINT_VERSION=v1.59.1

View File

@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.21.13
ARG GO_VERSION=1.22.7
ARG ALPINE_VERSION=3.20
ARG MODOUTDATED_VERSION=v0.8.0

View File

@ -1,4 +1,6 @@
---
title: Deprecated Docker Engine features
linkTitle: Deprecated features
aliases: ["/engine/misc/deprecated/"]
description: "Deprecated Features."
keywords: "docker, documentation, about, technology, deprecate"
@ -13,14 +15,12 @@ keywords: "docker, documentation, about, technology, deprecate"
will be rejected.
-->
# Deprecated Engine Features
This page provides an overview of features that are deprecated in Engine. Changes
in packaging, and supported (Linux) distributions are not included. To learn
about end of support for Linux distributions, refer to the
[release notes](https://docs.docker.com/engine/release-notes/).
## Feature Deprecation Policy
## Feature deprecation policy
As changes are made to Docker there may be times when existing features need to
be removed or replaced with newer features. Before an existing feature is removed
@ -32,35 +32,38 @@ Users are expected to take note of the list of deprecated features each release
and plan their migration away from those features, and (if applicable) towards
the replacement features as soon as possible.
## Deprecated Engine Features
## Deprecated engine features
The table below provides an overview of the current status of deprecated features:
The following table provides an overview of the current status of deprecated features:
- **Deprecated**: the feature is marked "deprecated" and should no longer be used.
The feature may be removed, disabled, or change behavior in a future release.
The _"Deprecated"_ column contains the release in which the feature was marked
The _"Deprecated"_ column contains the release in which the feature was marked
deprecated, whereas the _"Remove"_ column contains a tentative release in which
the feature is to be removed. If no release is included in the _"Remove"_ column,
the release is yet to be decided on.
- **Removed**: the feature was removed, disabled, or hidden. Refer to the linked
section for details. Some features are "soft" deprecated, which means that they
remain functional for backward compatibility, and to allow users to migrate to
alternatives. In such cases, a warning may be printed, and users should not rely
on this feature.
- **Removed**: the feature was removed, disabled, or hidden.
Refer to the linked section for details. Some features are "soft" deprecated,
which means that they remain functional for backward compatibility, and to
allow users to migrate to alternatives. In such cases, a warning may be
printed, and users should not rely on this feature.
| Status | Feature | Deprecated | Remove |
|------------|------------------------------------------------------------------------------------------------------------------------------------|------------|--------|
| Deprecated | [Non-standard fields in image inspect](#non-standard-fields-in-image-inspect) | v27.0 | v28.0 |
| Deprecated | [API CORS headers](#api-cors-headers) | v27.0 | v28.0 |
| Removed | [API CORS headers](#api-cors-headers) | v27.0 | v28.0 |
| Deprecated | [Graphdriver plugins (experimental)](#graphdriver-plugins-experimental) | v27.0 | v28.0 |
| Deprecated | [Unauthenticated TCP connections](#unauthenticated-tcp-connections) | v26.0 | v28.0 |
| Deprecated | [`Container` and `ContainerConfig` fields in Image inspect](#container-and-containerconfig-fields-in-image-inspect) | v25.0 | v26.0 |
| Deprecated | [Deprecate legacy API versions](#deprecate-legacy-api-versions) | v25.0 | v26.0 |
| Removed | [Container short ID in network Aliases field](#container-short-id-in-network-aliases-field) | v25.0 | v26.0 |
| Deprecated | [IsAutomated field, and "is-automated" filter on docker search](#isautomated-field-and-is-automated-filter-on-docker-search) | v25.0 | v26.0 |
| Deprecated | [IsAutomated field, and `is-automated` filter on `docker search`](#isautomated-field-and-is-automated-filter-on-docker-search) | v25.0 | v26.0 |
| Removed | [logentries logging driver](#logentries-logging-driver) | v24.0 | v25.0 |
| Removed | [OOM-score adjust for the daemon](#oom-score-adjust-for-the-daemon) | v24.0 | v25.0 |
| Removed | [Buildkit build information](#buildkit-build-information) | v23.0 | v24.0 |
| Removed | [BuildKit build information](#buildkit-build-information) | v23.0 | v24.0 |
| Deprecated | [Legacy builder for Linux images](#legacy-builder-for-linux-images) | v23.0 | - |
| Deprecated | [Legacy builder fallback](#legacy-builder-fallback) | v23.0 | - |
| Removed | [Btrfs storage driver on CentOS 7 and RHEL 7](#btrfs-storage-driver-on-centos-7-and-rhel-7) | v20.10 | v23.0 |
@ -91,7 +94,7 @@ The table below provides an overview of the current status of deprecated feature
| Removed | [Asynchronous `service create` and `service update` as default](#asynchronous-service-create-and-service-update-as-default) | v17.05 | v17.10 |
| Removed | [`-g` and `--graph` flags on `dockerd`](#-g-and---graph-flags-on-dockerd) | v17.05 | v23.0 |
| Deprecated | [Top-level network properties in NetworkSettings](#top-level-network-properties-in-networksettings) | v1.13 | v17.12 |
| Removed | [`filter` param for `/images/json` endpoint](#filter-param-for-imagesjson-endpoint) | v1.13 | v20.10 |
| Removed | [`filter` option for `/images/json` endpoint](#filter-option-for-imagesjson-endpoint) | v1.13 | v20.10 |
| Removed | [`repository:shortid` image references](#repositoryshortid-image-references) | v1.13 | v17.12 |
| Removed | [`docker daemon` subcommand](#docker-daemon-subcommand) | v1.13 | v17.12 |
| Removed | [Duplicate keys with conflicting values in engine labels](#duplicate-keys-with-conflicting-values-in-engine-labels) | v1.13 | v17.12 |
@ -122,8 +125,8 @@ The table below provides an overview of the current status of deprecated feature
The `Config` field returned shown in `docker image inspect` (and as returned by
the `GET /images/{name}/json` API endpoint) returns additional fields that are
not part of the image's configuration and not part of the [Docker Image Spec]
and [OCI Image Specification].
not part of the image's configuration and not part of the [Docker image specification]
and [OCI image specification].
These fields are never set (and always return the default value for the type),
but are not omitted in the response when left empty. As these fields were not
@ -131,7 +134,7 @@ intended to be part of the image configuration response, they are deprecated,
and will be removed from the API in thee next release.
The following fields are currently included in the API response, but are not
part of the underlying image's Config, and deprecated:
part of the underlying image's `Config` field, and deprecated:
- `Hostname`
- `Domainname`
@ -146,8 +149,8 @@ part of the underlying image's Config, and deprecated:
- `MacAddress` (already omitted unless set)
- `StopTimeout` (already omitted unless set)
[Docker image spec]: https://github.com/moby/docker-image-spec/blob/v1.3.1/specs-go/v1/image.go#L19-L32
[OCI Image Spec]: https://github.com/opencontainers/image-spec/blob/v1.1.0/specs-go/v1/config.go#L24-L62
[Docker image specification]: https://github.com/moby/docker-image-spec/blob/v1.3.1/specs-go/v1/image.go#L19-L32
[OCI image specification]: https://github.com/opencontainers/image-spec/blob/v1.1.0/specs-go/v1/config.go#L24-L62
### Graphdriver plugins (experimental)
@ -174,18 +177,19 @@ and a custom [snapshotter](https://github.com/containerd/containerd/tree/v1.7.18
### API CORS headers
**Deprecated in Release: v27.0**
**Target For Removal In Release: v28.0**
**Disabled by default in Release: v27.0**
**Removed in release: v28.0**
The `api-cors-header` configuration option for the Docker daemon is insecure,
and is therefore deprecated and scheduled for removal.
Incorrectly setting this option could leave a window of opportunity
for unauthenticated cross-origin requests to be accepted by the daemon.
Starting in Docker Engine v27.0, this flag can still be set,
In Docker Engine v27.0, this flag can still be set,
but it has no effect unless the environment variable
`DOCKERD_DEPRECATED_CORS_HEADER` is also set to a non-empty value.
This flag will be removed altogether in v28.0.
This flag has been removed altogether in v28.0.
This is a breaking change for authorization plugins and other programs
that depend on this option for accessing the Docker API from a browser.
@ -211,7 +215,7 @@ transit and providing a mechanism for mutual authentication.
For environments remote daemon access isn't required,
we recommend binding the Docker daemon to a Unix socket.
For daemon's where remote access is required and where TLS encryption is not feasible,
For daemons where remote access is required and where TLS encryption is not feasible,
you may want to consider using SSH as an alternative solution.
For further information, assistance, and step-by-step instructions on
@ -255,19 +259,19 @@ daemon may be updated to the latest release, but not all clients may be up-to-da
or vice versa). Support for API versions before that (API versions provided by
EOL versions of the Docker Daemon) is provided on a "best effort" basis.
Use of old API versions is very rare, and support for legacy API versions
Use of old API versions is rare, and support for legacy API versions
involves significant complexity (Docker 1.0.0 having been released 10 years ago).
Because of this, we'll start deprecating support for legacy API versions.
Docker Engine v25.0 by default disables API version older than 1.24 (aligning
the minimum supported API version between Linux and Windows daemons). When
connecting with a client that uses an API version version older than 1.24,
the daemon returns an error. The following example configures the docker
connecting with a client that uses an API version older than 1.24,
the daemon returns an error. The following example configures the Docker
CLI to use API version 1.23, which produces an error:
```console
DOCKER_API_VERSION=1.23 docker version
Error response from daemon: client version 1.23 is too old. Minimum supported API version is 1.24,
Error response from daemon: client version 1.23 is too old. Minimum supported API version is 1.24,
upgrade your client to a newer version
```
@ -301,12 +305,12 @@ A new field `DNSNames` containing the container name (if one was specified),
the hostname, the network aliases, as well as the container short ID, has been
introduced in v25.0 and should be used instead of the `Aliases` field.
### IsAutomated field, and "is-automated" filter on docker search
### IsAutomated field, and `is-automated` filter on `docker search`
**Deprecated in Release: v25.0**
**Target For Removal In Release: v26.0**
The "is_automated" field has been deprecated by Docker Hub's search API.
The `is_automated` field has been deprecated by Docker Hub's search API.
Consequently, the `IsAutomated` field in image search will always be set
to `false` in future, and searching for "is-automated=true" will yield no
results.
@ -346,7 +350,7 @@ Users currently depending on this feature are recommended to adjust the
daemon's OOM score using systemd or through other means, when starting
the daemon.
### Buildkit build information
### BuildKit build information
**Deprecated in Release: v23.0**
**Removed in Release: v24.0**
@ -354,7 +358,7 @@ the daemon.
[Build information](https://github.com/moby/buildkit/blob/v0.11/docs/buildinfo.md)
structures have been introduced in [BuildKit v0.10.0](https://github.com/moby/buildkit/releases/tag/v0.10.0)
and are generated with build metadata that allows you to see all the sources
(images, git repositories) that were used by the build with their exact
(images, Git repositories) that were used by the build with their exact
versions and also the configuration that was passed to the build. This
information is also embedded into the image configuration if one is generated.
@ -389,7 +393,7 @@ you to report issues in the [BuildKit issue tracker on GitHub](https://github.co
> `docker build` continues to use the classic builder to build native Windows
> images on Windows daemons.
### Legacy builder fallback
### Legacy builder fallback
**Deprecated in Release: v23.0**
@ -402,11 +406,11 @@ To provide a smooth transition to BuildKit as the default builder, Docker v23.0
has an automatic fallback for some situations, or produces an error to assist
users to resolve the problem.
In situations where the user did not explicitly opt-in to use BuildKit (i.e.,
In situations where the user did not explicitly opt-in to use BuildKit (i.e.,
`DOCKER_BUILDKIT=1` is not set), the CLI automatically falls back to the classic
builder, but prints a deprecation warning:
```
```text
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/
@ -420,7 +424,7 @@ and use BuildKit for your builds, or opt-out of using BuildKit with `DOCKER_BUIL
If you opted-in to use BuildKit (`DOCKER_BUILDKIT=1`), but the Buildx component
is missing, an error is printed instead, and the `docker build` command fails:
```
```text
ERROR: BuildKit is enabled but the buildx component is missing or broken.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/
@ -470,27 +474,27 @@ to decrypt the private key, and store it un-encrypted to continue using it.
Following the deprecation of [Compose on Kubernetes](https://github.com/docker/compose-on-kubernetes),
support for Kubernetes in the `stack` and `context` commands has been removed from
the cli, and options related to this functionality are now either ignored, or may
the CLI, and options related to this functionality are now either ignored, or may
produce an error.
The following command-line flags are removed from the `docker context` subcommands:
- `--default-stack-orchestrator` - swarm is now the only (and default) orchestrator for stacks.
- `--kubernetes` - the kubernetes endpoint can no longer be stored in `docker context`.
- `--kubernetes` - the Kubernetes endpoint can no longer be stored in `docker context`.
- `--kubeconfig` - exporting a context as a kubeconfig file is no longer supported.
The output produced by the `docker context inspect` subcommand no longer contains
information about `StackOrchestrator` and `Kubernetes` endpoints for new contexts.
The following command-line flags are removed from the `docker stack` subcommands:
- `--kubeconfig` - using a kubeconfig file as context is no longer supported.
- `--namespace` - configuring the kubernetes namespace for stacks is no longer supported.
- `--namespace` - configuring the Kubernetes namespace for stacks is no longer supported.
- `--orchestrator` - swarm is now the only (and default) orchestrator for stacks.
The `DOCKER_STACK_ORCHESTRATOR`, `DOCKER_ORCHESTRATOR`, and `KUBECONFIG` environment
variables, as well as the `stackOrchestrator` option in the `~/.docker/config.json`
cli configuration file are no longer used, and ignored.
CLI configuration file are no longer used, and ignored.
### Pulling images from non-compliant image registries
@ -532,7 +536,7 @@ major release.
The experimental feature to run Linux containers on Windows (LCOW) was introduced
as a technical preview in Docker 17.09. While many enhancements were made after
its introduction, the feature never reached completeness, and development has
now stopped in favor of running docker natively on Linux in WSL2.
now stopped in favor of running Docker natively on Linux in WSL2.
Developers who want to run Linux workloads on a Windows host are encouraged to use
[Docker Desktop with WSL2](https://docs.docker.com/docker-for-windows/wsl/) instead.
@ -565,11 +569,11 @@ take no effect.
> [!NOTE]
> While not deprecated (yet) in Docker, the OCI runtime specification also
> deprecated the `memory.kmem.tcp.limit_in_bytes` option. When using `runc` as
> runtime, this option takes no effect. The linux kernel did not explicitly
> runtime, this option takes no effect. The Linux kernel did not explicitly
> deprecate this feature, and there is a tracking ticket in the `runc` issue
> tracker to determine if this option should be reinstated or if this was an
> oversight of the Linux kernel maintainers (see [opencontainers/runc#3174](https://github.com/opencontainers/runc/issues/3174)).
>
>
> The `memory.kmem.tcp.limit_in_bytes` option is only supported with cgroups v1,
> and not available on installations running with cgroups v2. This option is
> only supported by the API, and not exposed on the `docker` command-line.
@ -588,7 +592,7 @@ networks using an external key/value store. The corresponding`--cluster-advertis
**Deprecated in Release: v20.10**
**Removed in Release: v23.0**
The docker CLI up until v1.7.0 used the `~/.dockercfg` file to store credentials
The Docker CLI up until v1.7.0 used the `~/.dockercfg` file to store credentials
after authenticating to a registry (`docker login`). Docker v1.7.0 replaced this
file with a new CLI configuration file, located in `~/.docker/config.json`. When
implementing the new configuration file, the old file (and file-format) was kept
@ -722,8 +726,7 @@ to Docker Enterprise, using an image-based distribution of the Docker Engine.
This feature was only available on Linux, and only when executed on a local node.
Given the limitations of this feature, and the feature not getting widely adopted,
the `docker engine` subcommands will be removed, in favor of installation through
standard package managers.
standard package managers.
### Top-level `docker deploy` subcommand (experimental)
@ -736,7 +739,6 @@ The top-level `docker deploy` command (using the "Docker Application Bundle"
17.03, but superseded by support for Docker Compose files using the `docker stack deploy`
subcommand.
### `docker stack deploy` using "dab" files (experimental)
**Deprecated in Release: v19.03**
@ -744,7 +746,7 @@ subcommand.
**Removed in Release: v20.10**
With no development being done on this feature, and no active use of the file
format, support for the DAB file format and the top-level docker deploy command
format, support for the DAB file format and the top-level `docker deploy` command
(hidden by default in 19.03), will be removed, in favour of `docker stack deploy`
using compose files.
@ -785,12 +787,12 @@ maintenance of the `aufs` storage driver.
The `overlay` storage driver is deprecated in favor of the `overlay2` storage
driver, which has all the benefits of `overlay`, without its limitations (excessive
inode consumption). The legacy `overlay` storage driver has been removed in
inode consumption). The legacy `overlay` storage driver has been removed in
Docker Engine v24.0. Users of the `overlay` storage driver should migrate to the
`overlay2` storage driver before upgrading to Docker Engine v24.0.
The legacy `overlay` storage driver allowed using overlayFS-backed filesystems
on pre 4.x kernels. Now that all supported distributions are able to run `overlay2`
on kernels older than v4.x. Now that all supported distributions are able to run `overlay2`
(as they are either on kernel 4.x, or have support for multiple lowerdirs
backported), there is no reason to keep maintaining the `overlay` storage driver.
@ -824,7 +826,6 @@ were always documented to be reserved, but there was never any enforcement.
Usage of these namespaces will now cause a warning in the engine logs to discourage their
use, and will error instead in v20.10 and above.
### `--disable-legacy-registry` override daemon option
**Disabled In Release: v17.12**
@ -835,7 +836,6 @@ The `--disable-legacy-registry` flag was disabled in Docker 17.12 and will print
an error when used. For this error to be printed, the flag itself is still present,
but hidden. The flag has been removed in Docker 19.03.
### Interacting with V1 registries
**Disabled By Default In Release: v17.06**
@ -843,7 +843,7 @@ but hidden. The flag has been removed in Docker 19.03.
**Removed In Release: v17.12**
Version 1.8.3 added a flag (`--disable-legacy-registry=false`) which prevents the
docker daemon from `pull`, `push`, and `login` operations against v1
Docker daemon from `pull`, `push`, and `login` operations against v1
registries. Though enabled by default, this signals the intent to deprecate
the v1 protocol.
@ -855,7 +855,6 @@ Starting with Docker 17.12, support for V1 registries has been removed, and the
`--disable-legacy-registry` flag can no longer be used, and `dockerd` will fail to
start when set.
### Asynchronous `service create` and `service update` as default
**Deprecated In Release: v17.05**
@ -895,20 +894,22 @@ about the default ("bridge") network;
These properties are deprecated in favor of per-network properties in
`NetworkSettings.Networks`. These properties were already "deprecated" in
docker 1.9, but kept around for backward compatibility.
Docker 1.9, but kept around for backward compatibility.
Refer to [#17538](https://github.com/docker/docker/pull/17538) for further
information.
### `filter` param for `/images/json` endpoint
### `filter` option for `/images/json` endpoint
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Removed In Release: v20.10**
The `filter` param to filter the list of image by reference (name or name:tag)
The `filter` option to filter the list of image by reference (name or name:tag)
is now implemented as a regular filter, named `reference`.
### `repository:shortid` image references
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Removed In Release: v17.12**
@ -920,6 +921,7 @@ Support for the `repository:shortid` notation to reference images was removed
in Docker 17.12.
### `docker daemon` subcommand
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Removed In Release: v17.12**
@ -927,6 +929,7 @@ in Docker 17.12.
The daemon is moved to a separate binary (`dockerd`), and should be used instead.
### Duplicate keys with conflicting values in engine labels
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Removed In Release: v17.12**
@ -935,11 +938,13 @@ When setting duplicate keys with conflicting values, an error will be produced,
will fail to start.
### `MAINTAINER` in Dockerfile
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
`MAINTAINER` was an early very limited form of `LABEL` which should be used instead.
### API calls without a version
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Target For Removal In Release: v17.12**
@ -949,6 +954,7 @@ future Engine versions. Instead of just requesting, for example, the URL
`/containers/json`, you must now request `/v1.25/containers/json`.
### Backing filesystem without `d_type` support for overlay/overlay2
**Deprecated In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
**Removed In Release: v17.12**
@ -963,7 +969,6 @@ backing filesystem without `d_type` support.
Refer to [#27358](https://github.com/docker/docker/issues/27358) for details.
### `--automated` and `--stars` flags on `docker search`
**Deprecated in Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)**
@ -973,7 +978,6 @@ Refer to [#27358](https://github.com/docker/docker/issues/27358) for details.
The `docker search --automated` and `docker search --stars` options are deprecated.
Use `docker search --filter=is-automated=<true|false>` and `docker search --filter=stars=...` instead.
### `-h` shorthand for `--help`
**Deprecated In Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)**
@ -986,13 +990,15 @@ on all subcommands (due to it conflicting with, e.g. `-h` / `--hostname` on
"usage" output of subcommands, nor documented, and is now marked "deprecated".
### `-e` and `--email` flags on `docker login`
**Deprecated In Release: [v1.11.0](https://github.com/docker/docker/releases/tag/v1.11.0)**
**Removed In Release: [v17.06](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce)**
The docker login command is removing the ability to automatically register for an account with the target registry if the given username doesn't exist. Due to this change, the email flag is no longer required, and will be deprecated.
The `docker login` no longer automatically registers an account with the target registry if the given username doesn't exist. Due to this change, the email flag is no longer required, and will be deprecated.
### Separator (`:`) of `--security-opt` flag on `docker run`
**Deprecated In Release: [v1.11.0](https://github.com/docker/docker/releases/tag/v1.11.0)**
**Target For Removal In Release: v17.06**
@ -1000,12 +1006,14 @@ The docker login command is removing the ability to automatically register for a
The flag `--security-opt` doesn't use the colon separator (`:`) anymore to divide keys and values, it uses the equal symbol (`=`) for consistency with other similar flags, like `--storage-opt`.
### Ambiguous event fields in API
**Deprecated In Release: [v1.10.0](https://github.com/docker/docker/releases/tag/v1.10.0)**
The fields `ID`, `Status` and `From` in the events API have been deprecated in favor of a more rich structure.
See the events API documentation for the new format.
### `-f` flag on `docker tag`
**Deprecated In Release: [v1.10.0](https://github.com/docker/docker/releases/tag/v1.10.0)**
**Removed In Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)**
@ -1013,6 +1021,7 @@ See the events API documentation for the new format.
To make tagging consistent across the various `docker` commands, the `-f` flag on the `docker tag` command is deprecated. It is no longer necessary to specify `-f` to move a tag from one image to another. Nor will `docker` generate an error if the `-f` flag is missing and the specified tag is already in use.
### HostConfig at API container start
**Deprecated In Release: [v1.10.0](https://github.com/docker/docker/releases/tag/v1.10.0)**
**Removed In Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)**
@ -1029,8 +1038,8 @@ defining it at container creation (`POST /containers/create`).
The `docker ps --before` and `docker ps --since` options are deprecated.
Use `docker ps --filter=before=...` and `docker ps --filter=since=...` instead.
### Driver-specific log tags
**Deprecated In Release: [v1.9.0](https://github.com/docker/docker/releases/tag/v1.9.0)**
**Removed In Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)**
@ -1043,8 +1052,8 @@ Because of which, the driver specific log tag options `syslog-tag`, `gelf-tag` a
$ docker --log-driver=syslog --log-opt tag="{{.ImageName}}/{{.Name}}/{{.ID}}"
```
### Docker Content Trust ENV passphrase variables name change
**Deprecated In Release: [v1.9.0](https://github.com/docker/docker/releases/tag/v1.9.0)**
**Removed In Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)**
@ -1054,7 +1063,6 @@ Since 1.9, Docker Content Trust Offline key has been renamed to Root key and the
- DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE is now named DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE
- DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE is now named DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE
### `/containers/(id or name)/copy` endpoint
**Deprecated In Release: [v1.8.0](https://github.com/docker/docker/releases/tag/v1.8.0)**
@ -1063,63 +1071,61 @@ Since 1.9, Docker Content Trust Offline key has been renamed to Root key and the
The endpoint `/containers/(id or name)/copy` is deprecated in favor of `/containers/(id or name)/archive`.
### LXC built-in exec driver
**Deprecated In Release: [v1.8.0](https://github.com/docker/docker/releases/tag/v1.8.0)**
**Removed In Release: [v1.10.0](https://github.com/docker/docker/releases/tag/v1.10.0)**
The built-in LXC execution driver, the lxc-conf flag, and API fields have been removed.
### Old Command Line Options
**Deprecated In Release: [v1.8.0](https://github.com/docker/docker/releases/tag/v1.8.0)**
**Removed In Release: [v1.10.0](https://github.com/docker/docker/releases/tag/v1.10.0)**
The flags `-d` and `--daemon` are deprecated in favor of the `daemon` subcommand:
docker daemon -H ...
The flags `-d` and `--daemon` are deprecated. Use the separate `dockerd` binary instead.
The following single-dash (`-opt`) variant of certain command line options
are deprecated and replaced with double-dash options (`--opt`):
docker attach -nostdin
docker attach -sig-proxy
docker build -no-cache
docker build -rm
docker commit -author
docker commit -run
docker events -since
docker history -notrunc
docker images -notrunc
docker inspect -format
docker ps -beforeId
docker ps -notrunc
docker ps -sinceId
docker rm -link
docker run -cidfile
docker run -dns
docker run -entrypoint
docker run -expose
docker run -link
docker run -lxc-conf
docker run -n
docker run -privileged
docker run -volumes-from
docker search -notrunc
docker search -stars
docker search -t
docker search -trusted
docker tag -force
- `docker attach -nostdin`
- `docker attach -sig-proxy`
- `docker build -no-cache`
- `docker build -rm`
- `docker commit -author`
- `docker commit -run`
- `docker events -since`
- `docker history -notrunc`
- `docker images -notrunc`
- `docker inspect -format`
- `docker ps -beforeId`
- `docker ps -notrunc`
- `docker ps -sinceId`
- `docker rm -link`
- `docker run -cidfile`
- `docker run -dns`
- `docker run -entrypoint`
- `docker run -expose`
- `docker run -link`
- `docker run -lxc-conf`
- `docker run -n`
- `docker run -privileged`
- `docker run -volumes-from`
- `docker search -notrunc`
- `docker search -stars`
- `docker search -t`
- `docker search -trusted`
- `docker tag -force`
The following double-dash options are deprecated and have no replacement:
docker run --cpuset
docker run --networking
docker ps --since-id
docker ps --before-id
docker search --trusted
- `docker run --cpuset`
- `docker run --networking`
- `docker ps --since-id`
- `docker ps --before-id`
- `docker search --trusted`
**Deprecated In Release: [v1.5.0](https://github.com/docker/docker/releases/tag/v1.5.0)**
@ -1127,11 +1133,7 @@ The following double-dash options are deprecated and have no replacement:
The single-dash (`-help`) was removed, in favor of the double-dash `--help`
docker -help
docker [COMMAND] -help
### `--api-enable-cors` flag on dockerd
### `--api-enable-cors` flag on `dockerd`
**Deprecated In Release: [v1.6.0](https://github.com/docker/docker/releases/tag/v1.6.0)**
@ -1140,19 +1142,19 @@ The single-dash (`-help`) was removed, in favor of the double-dash `--help`
The flag `--api-enable-cors` is deprecated since v1.6.0. Use the flag
`--api-cors-header` instead.
### `--run` flag on docker commit
### `--run` flag on `docker commit`
**Deprecated In Release: [v0.10.0](https://github.com/docker/docker/releases/tag/v0.10.0)**
**Removed In Release: [v1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)**
The flag `--run` of the docker commit (and its short version `-run`) were deprecated in favor
The flag `--run` of the `docker commit` command (and its short version `-run`) were deprecated in favor
of the `--changes` flag that allows to pass `Dockerfile` commands.
### Three arguments form in `docker import`
**Deprecated In Release: [v0.6.7](https://github.com/docker/docker/releases/tag/v0.6.7)**
**Removed In Release: [v1.12.0](https://github.com/docker/docker/releases/tag/v1.12.0)**
The `docker import` command format `file|URL|- [REPOSITORY [TAG]]` is deprecated since November 2013. It's no more supported.
The `docker import` command format `file|URL|- [REPOSITORY [TAG]]` is deprecated since November 2013. It's no longer supported.

View File

@ -1,5 +1,6 @@
---
title: Docker Engine managed plugin system
linkTitle: Docker Engine plugins
description: Develop and use a plugin with the managed plugin system
keywords: "API, Usage, plugins, documentation, developer"
aliases:

View File

@ -8,7 +8,7 @@ keywords: "Examples, Usage, plugins, docker, documentation, user guide"
This document describes the Docker Engine plugins generally available in Docker
Engine. To view information on plugins managed by Docker,
refer to [Docker Engine plugin system](index.md).
refer to [Docker Engine plugin system](_index.md).
You can extend the capabilities of the Docker Engine by loading third-party
plugins. This page explains the types of plugins and provides links to several
@ -16,7 +16,7 @@ volume and network plugins for Docker.
## Types of plugins
Plugins extend Docker's functionality. They come in specific types. For
Plugins extend Docker's functionality. They come in specific types. For
example, a [volume plugin](plugins_volume.md) might enable Docker
volumes to persist across multiple Docker hosts and a
[network plugin](plugins_network.md) might provide network plumbing.

View File

@ -8,7 +8,7 @@ Docker plugins are out-of-process extensions which add capabilities to the
Docker Engine.
This document describes the Docker Engine plugin API. To view information on
plugins managed by Docker Engine, refer to [Docker Engine plugin system](index.md).
plugins managed by Docker Engine, refer to [Docker Engine plugin system](_index.md).
This page is intended for people who want to develop their own Docker plugin.
If you just want to learn about or use Docker plugins, look

View File

@ -8,7 +8,7 @@ aliases:
This document describes the Docker Engine plugins available in Docker
Engine. To view information on plugins managed by Docker Engine,
refer to [Docker Engine plugin system](index.md).
refer to [Docker Engine plugin system](_index.md).
Docker's out-of-the-box authorization model is all or nothing. Any user with
permission to access the Docker daemon can run any Docker client command. The

View File

@ -6,12 +6,12 @@ keywords: "Examples, Usage, plugins, docker, documentation, user guide"
This document describes Docker Engine network driver plugins generally
available in Docker Engine. To view information on plugins
managed by Docker Engine, refer to [Docker Engine plugin system](index.md).
managed by Docker Engine, refer to [Docker Engine plugin system](_index.md).
Docker Engine network plugins enable Engine deployments to be extended to
support a wide range of networking technologies, such as VXLAN, IPVLAN, MACVLAN
or something completely different. Network driver plugins are supported via the
LibNetwork project. Each plugin is implemented as a "remote driver" for
LibNetwork project. Each plugin is implemented as a "remote driver" for
LibNetwork, which shares plugin infrastructure with Engine. Effectively, network
driver plugins are activated in the same way as other plugins, and use the same
kind of protocol.
@ -19,7 +19,7 @@ kind of protocol.
## Network plugins and Swarm mode
[Legacy plugins](legacy_plugins.md) do not work in Swarm mode. However,
plugins written using the [v2 plugin system](index.md) do work in Swarm mode, as
plugins written using the [v2 plugin system](_index.md) do work in Swarm mode, as
long as they are installed on each Swarm worker node.
## Use network driver plugins

View File

@ -1234,7 +1234,7 @@ the container and remove the file system when the container exits, use the
`--rm` flag:
```text
--rm=false: Automatically remove the container when it exits
--rm: Automatically remove the container when it exits
```
> [!NOTE]

View File

@ -29,7 +29,7 @@ The base command for the Docker CLI.
| [`inspect`](inspect.md) | Return low-level information on Docker objects |
| [`kill`](kill.md) | Kill one or more running containers |
| [`load`](load.md) | Load an image from a tar archive or STDIN |
| [`login`](login.md) | Log in to a registry |
| [`login`](login.md) | Authenticate to a registry |
| [`logout`](logout.md) | Log out from a registry |
| [`logs`](logs.md) | Fetch the logs of a container |
| [`manifest`](manifest.md) | Manage Docker image manifests and manifest lists |

View File

@ -1,60 +1,51 @@
# login
<!---MARKER_GEN_START-->
Log in to a registry.
If no server is specified, the default is defined by the daemon.
Authenticate to a registry.
Defaults to Docker Hub if no server is specified.
### Options
| Name | Type | Default | Description |
|:--------------------------------------|:---------|:--------|:-----------------------------|
| `-p`, `--password` | `string` | | Password |
| [`--password-stdin`](#password-stdin) | `bool` | | Take the password from stdin |
| `-u`, `--username` | `string` | | Username |
| Name | Type | Default | Description |
|:---------------------------------------------|:---------|:--------|:-----------------------------|
| `-p`, `--password` | `string` | | Password |
| [`--password-stdin`](#password-stdin) | `bool` | | Take the password from stdin |
| [`-u`](#username), [`--username`](#username) | `string` | | Username |
<!---MARKER_GEN_END-->
## Description
Log in to a registry.
Authenticate to a registry.
## Examples
You can authenticate to any public or private registry for which you have
credentials. Authentication may be required for pulling and pushing images.
Other commands, such as `docker scout` and `docker build`, may also require
authentication to access subscription-only features or data related to your
Docker organization.
### Login to a self-hosted registry
Authentication credentials are stored in the configured [credential
store](#credential-stores). If you use Docker Desktop, credentials are
automatically saved to the native keychain of your operating system. If you're
not using Docker Desktop, you can configure the credential store in the Docker
configuration file, which is located at `$HOME/.docker/config.json` on Linux or
`%USERPROFILE%/.docker/config.json` on Windows. If you don't configure a
credential store, Docker stores credentials in the `config.json` file in a
base64-encoded format. This method is less secure than configuring and using a
credential store.
If you want to log in to a self-hosted registry you can specify this by
adding the server name.
`docker login` also supports [credential helpers](#credential-helpers) to help
you handle credentials for specific registries.
```console
$ docker login localhost:8080
```
### Authentication methods
### <a name="password-stdin"></a> Provide a password using STDIN (--password-stdin)
To run the `docker login` command non-interactively, you can set the
`--password-stdin` flag to provide a password through `STDIN`. Using
`STDIN` prevents the password from ending up in the shell's history,
or log-files.
The following example reads a password from a file, and passes it to the
`docker login` command using `STDIN`:
```console
$ cat ~/my_password.txt | docker login --username foo --password-stdin
```
### Privileged user requirement
`docker login` requires you to use `sudo` or be `root`, except when:
- Connecting to a remote daemon, such as a `docker-machine` provisioned `docker engine`.
- The user is added to the `docker` group. This will impact the security of your system; the `docker` group is `root` equivalent. See [Docker Daemon Attack Surface](https://docs.docker.com/engine/security/#docker-daemon-attack-surface) for details.
You can log in to any public or private repository for which you have
credentials. When you log in, the command stores credentials in
`$HOME/.docker/config.json` on Linux or `%USERPROFILE%/.docker/config.json` on
Windows, via the procedure described below.
You can authenticate to a registry using a username and access token or
password. Docker Hub also supports a web-based sign-in flow, which signs you in
to your Docker account without entering your password. For Docker Hub, the
`docker login` command uses a device code flow by default, unless the
`--username` flag is specified. The device code flow is a secure way to sign
in. See [Authenticate to Docker Hub using device code](#authenticate-to-docker-hub-using-device-code).
### Credential stores
@ -75,6 +66,10 @@ Helpers are available for the following credential stores:
- Microsoft Windows Credential Manager
- [pass](https://www.passwordstore.org/)
With Docker Desktop, the credential store is already installed and configured
for you. Unless you want to change the credential store used by Docker Desktop,
you can skip the following steps.
#### Configure the credential store
You need to specify the credential store in `$HOME/.docker/config.json`
@ -94,22 +89,22 @@ the credentials from the file and run `docker login` again.
#### Default behavior
By default, Docker looks for the native binary on each of the platforms, i.e.
"osxkeychain" on macOS, "wincred" on windows, and "pass" on Linux. A special
case is that on Linux, Docker will fall back to the "secretservice" binary if
it cannot find the "pass" binary. If none of these binaries are present, it
stores the credentials (i.e. password) in base64 encoding in the config files
described above.
`osxkeychain` on macOS, `wincred` on Windows, and `pass` on Linux. A special
case is that on Linux, Docker will fall back to the `secretservice` binary if
it cannot find the `pass` binary. If none of these binaries are present, it
stores the base64-encoded credentials in the `config.json` configuration file.
#### Credential helper protocol
Credential helpers can be any program or script that follows a very simple protocol.
This protocol is heavily inspired by Git, but it differs in the information shared.
Credential helpers can be any program or script that implements the credential
helper protocol. This protocol is inspired by Git, but differs in the
information shared.
The helpers always use the first argument in the command to identify the action.
There are only three possible values for that argument: `store`, `get`, and `erase`.
The `store` command takes a JSON payload from the standard input. That payload carries
the server address, to identify the credential, the user name, and either a password
the server address, to identify the credential, the username, and either a password
or an identity token.
```json
@ -149,10 +144,10 @@ will show if there was an issue.
### Credential helpers
Credential helpers are similar to the credential store above, but act as the
designated programs to handle credentials for specific registries. The default
credential store (`credsStore` or the config file itself) will not be used for
operations concerning credentials of the specified registries.
Credential helpers are similar to [credential stores](#credential-stores), but
act as the designated programs to handle credentials for specific registries.
The default credential store will not be used for operations concerning
credentials of the specified registries.
#### Configure credential helpers
@ -162,19 +157,93 @@ the credentials from the default store.
Credential helpers are specified in a similar way to `credsStore`, but
allow for multiple helpers to be configured at a time. Keys specify the
registry domain, and values specify the suffix of the program to use
(i.e. everything after `docker-credential-`).
For example:
(i.e. everything after `docker-credential-`). For example:
```json
{
"credHelpers": {
"registry.example.com": "registryhelper",
"awesomereg.example.org": "hip-star",
"unicorn.example.io": "vcbait"
"myregistry.example.com": "secretservice",
"docker.internal.example": "pass",
}
}
```
## Examples
### Authenticate to Docker Hub with web-based login
By default, the `docker login` command authenticates to Docker Hub, using a
device code flow. This flow lets you authenticate to Docker Hub without
entering your password. Instead, you visit a URL in your web browser, enter a
code, and authenticate.
```console
$ docker login
USING WEB-BASED LOGIN
To sign in with credentials on the command line, use 'docker login -u <username>'
Your one-time device confirmation code is: LNFR-PGCJ
Press ENTER to open your browser or submit your device code here: https://login.docker.com/activate
Waiting for authentication in the browser…
```
After entering the code in your browser, you are authenticated to Docker Hub
using the account you're currently signed in with on the Docker Hub website or
in Docker Desktop. If you aren't signed in, you are prompted to sign in after
entering the device code.
### Authenticate to a self-hosted registry
If you want to authenticate to a self-hosted registry you can specify this by
adding the server name.
```console
$ docker login registry.example.com
```
By default, the `docker login` command assumes that the registry listens on
port 443 or 80. If the registry listens on a different port, you can specify it
by adding the port number to the server name.
```console
$ docker login registry.example.com:1337
```
> [!NOTE]
> Registry addresses should not include URL path components, only the hostname
> and (optionally) the port. Registry addresses with URL path components may
> result in an error. For example, `docker login registry.example.com/foo/`
> is incorrect, while `docker login registry.example.com` is correct.
>
> The exception to this rule is the Docker Hub registry, which may use the
> `/v1/` path component in the address for historical reasons.
### <a name="username"></a> Authenticate to a registry with a username and password
To authenticate to a registry with a username and password, you can use the
`--username` or `-u` flag. The following example authenticates to Docker Hub
with the username `moby`. The password is entered interactively.
```console
$ docker login -u moby
```
### <a name="password-stdin"></a> Provide a password using STDIN (--password-stdin)
To run the `docker login` command non-interactively, you can set the
`--password-stdin` flag to provide a password through `STDIN`. Using
`STDIN` prevents the password from ending up in the shell's history,
or log-files.
The following example reads a password from a file, and passes it to the
`docker login` command using `STDIN`:
```console
$ cat ~/my_password.txt | docker login --username foo --password-stdin
```
## Related commands
* [logout](logout.md)

View File

@ -25,7 +25,6 @@ A self-sufficient runtime for containers.
Options:
--add-runtime runtime Register an additional OCI compatible runtime (default [])
--allow-nondistributable-artifacts list Allow push of nondistributable artifacts to registry
--api-cors-header string Set CORS headers in the Engine API
--authorization-plugin list Authorization plugins to load
--bip string Specify network bridge IP
-b, --bridge string Attach containers to a network bridge
@ -57,6 +56,7 @@ Options:
--exec-opt list Runtime execution options
--exec-root string Root directory for execution state files (default "/var/run/docker")
--experimental Enable experimental features
--feature map Enable feature in the daemon
--fixed-cidr string IPv4 subnet for fixed IPs
--fixed-cidr-v6 string IPv6 subnet for fixed IPs
-G, --group string Group for the unix socket (default "docker")
@ -79,6 +79,7 @@ Options:
--label list Set key=value labels to the daemon
--live-restore Enable live restore of docker when containers are still running
--log-driver string Default driver for container logs (default "json-file")
--log-format string Set the logging format ("text"|"json") (default "text")
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--log-opt map Default log driver options for containers (default map[])
--max-concurrent-downloads int Set the max concurrent downloads (default 3)
@ -890,6 +891,33 @@ Alternatively, you can set custom locations for CDI specifications using the
When CDI is enabled for a daemon, you can view the configured CDI specification
directories using the `docker info` command.
#### <a name="log-format"></a> Daemon logging format
The `--log-format` option or "log-format" option in the [daemon configuration file](#daemon-configuration-file)
lets you set the format for logs produced by the daemon. The logging format should
only be configured either through the `--log-format` command line option or
through the "log-format" field in the configuration file; using both
the command-line option and the "log-format" field in the configuration
file produces an error. If this option is not set, the default is "text".
The following example configures the daemon through the `--log-format` command
line option to use `json` formatted logs;
```console
$ dockerd --log-format=json
# ...
{"level":"info","msg":"API listen on /var/run/docker.sock","time":"2024-09-16T11:06:08.558145428Z"}
```
The following example shows a `daemon.json` configuration file with the
"log-format" set;
```json
{
"log-format": "json"
}
```
### Miscellaneous options
IP masquerading uses address translation to allow containers without a public
@ -971,6 +999,36 @@ Example of usage:
}
```
### <a name="feature"></a> Enable feature in the daemon (--feature)
The `--feature` option lets you enable or disable a feature in the daemon.
This option corresponds with the "features" field in the [daemon.json configuration file](#daemon-configuration-file).
Features should only be configured either through the `--feature` command line
option or through the "features" field in the configuration file; using both
the command-line option and the "features" field in the configuration
file produces an error. The feature option can be specified multiple times
to configure multiple features. The `--feature` option accepts a name and
optional boolean value. When omitting the value, the default is `true`.
The following example runs the daemon with the `cdi` and `containerd-snapshotter`
features enabled. The `cdi` option is provided with a value;
```console
$ dockerd --feature cdi=true --feature containerd-snapshotter
```
The following example is the equivalent using the `daemon.json` configuration
file;
```json
{
"features": {
"cdi": true,
"containerd-snapshotter": true
}
}
```
### Daemon configuration file
The `--config-file` option allows you to set any configuration option
@ -1015,7 +1073,6 @@ The following is a full example of the allowed configuration options on Linux:
```json
{
"allow-nondistributable-artifacts": [],
"api-cors-header": "",
"authorization-plugins": [],
"bip": "",
"bridge": "",
@ -1065,7 +1122,10 @@ The following is a full example of the allowed configuration options on Linux:
"exec-opts": [],
"exec-root": "",
"experimental": false,
"features": {},
"features": {
"cdi": true,
"containerd-snapshotter": true
},
"fixed-cidr": "",
"fixed-cidr-v6": "",
"group": "",
@ -1089,6 +1149,7 @@ The following is a full example of the allowed configuration options on Linux:
"labels": [],
"live-restore": true,
"log-driver": "json-file",
"log-format": "text",
"log-level": "",
"log-opts": {
"cache-disabled": "false",
@ -1183,6 +1244,7 @@ The following is a full example of the allowed configuration options on Windows:
"insecure-registries": [],
"labels": [],
"log-driver": "",
"log-format": "text",
"log-level": "",
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5,

View File

@ -30,7 +30,7 @@ func TestOauthLogin(t *testing.T) {
assert.NilError(t, err)
output, _ := io.ReadAll(p)
assert.Check(t, strings.Contains(string(output), "USING WEB BASED LOGIN"), string(output))
assert.Check(t, strings.Contains(string(output), "USING WEB-BASED LOGIN"), string(output))
}
func TestLoginWithEscapeHatch(t *testing.T) {

View File

@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.21.13
ARG GO_VERSION=1.22.7
FROM golang:${GO_VERSION}-alpine AS generated
ENV GOTOOLCHAIN=local

View File

@ -7,7 +7,6 @@ dockerd - Enable daemon mode
**dockerd**
[**--add-runtime**[=*[]*]]
[**--allow-nondistributable-artifacts**[=*[]*]]
[**--api-cors-header**=[=*API-CORS-HEADER*]]
[**--authorization-plugin**[=*[]*]]
[**-b**|**--bridge**[=*BRIDGE*]]
[**--bip**[=*BIP*]]
@ -31,6 +30,7 @@ dockerd - Enable daemon mode
[**--exec-opt**[=*[]*]]
[**--exec-root**[=*/var/run/docker*]]
[**--experimental**[=**false**]]
[**--feature**[=*NAME*[=**true**|**false**]]
[**--fixed-cidr**[=*FIXED-CIDR*]]
[**--fixed-cidr-v6**[=*FIXED-CIDR-V6*]]
[**-G**|**--group**[=*docker*]]
@ -52,6 +52,7 @@ dockerd - Enable daemon mode
[**--label**[=*[]*]]
[**--live-restore**[=**false**]]
[**--log-driver**[=*json-file*]]
[**--log-format**="*text*|*json*"]
[**--log-opt**[=*map[]*]]
[**--mtu**[=*0*]]
[**--max-concurrent-downloads**[=*3*]]
@ -136,10 +137,6 @@ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-ru
artifacts to private registries and ensure that you are in compliance with
any terms that cover redistributing nondistributable artifacts.
**--api-cors-header**=""
Set CORS headers in the Engine API. Default is cors disabled. Give urls like
"http://foo, http://bar, ...". Give "\*" to allow all.
**--authorization-plugin**=""
Set authorization plugins to load
@ -222,6 +219,14 @@ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-ru
**--experimental**=""
Enable the daemon experimental features.
**--feature**=*NAME*[=**true**|**false**]
Enable or disable a feature in the daemon. This option corresponds
with the "features" field in the daemon.json configuration file. Using
both the command-line option and the "features" field in the configuration
file produces an error. The feature option can be specified multiple times
to configure multiple features.
Usage example: `--feature containerd-snapshotter` or `--feature containerd-snapshotter=true`.
**--fixed-cidr**=""
IPv4 subnet for fixed IPs (e.g., 10.20.0.0/16); this subnet must be nested in
the bridge subnet (which is defined by \-b or \-\-bip).
@ -324,6 +329,9 @@ unix://[/path/to/socket] to use.
Default driver for container logs. Default is **json-file**.
**Warning**: **docker logs** command works only for **json-file** logging driver.
**--log-format**="*text*|*json*"
Set the format for logs produced by the daemon. Default is "text".
**--log-opt**=[]
Logging driver specific options.

View File

@ -5,6 +5,12 @@
set -eu -o pipefail
# Disable CGO - we don't need it for these plugins.
#
# Important: this must be done before sourcing "./scripts/build/.variables",
# because some other variables are conditionally set whether CGO is enabled.
export CGO_ENABLED=0
source ./scripts/build/.variables
for p in cli-plugins/examples/* "$@" ; do
@ -15,5 +21,5 @@ for p in cli-plugins/examples/* "$@" ; do
mkdir -p "$(dirname "${TARGET_PLUGIN}")"
echo "Building $GO_LINKMODE $(basename "${TARGET_PLUGIN}")"
(set -x ; CGO_ENABLED=0 GO111MODULE=auto go build -o "${TARGET_PLUGIN}" -tags "${GO_BUILDTAGS}" -ldflags "${GO_LDFLAGS}" ${GO_BUILDMODE} "github.com/docker/cli/${p}")
(set -x ; GO111MODULE=auto go build -o "${TARGET_PLUGIN}" -tags "${GO_BUILDTAGS}" -ldflags "${GO_LDFLAGS}" "github.com/docker/cli/${p}")
done

View File

@ -7,7 +7,7 @@ module github.com/docker/cli
go 1.21.0
require (
dario.cat/mergo v1.0.0
dario.cat/mergo v1.0.1
github.com/containerd/platforms v0.2.1
github.com/creack/pty v1.1.21
github.com/distribution/reference v0.6.0
@ -32,6 +32,7 @@ require (
github.com/morikuni/aec v1.0.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.1
@ -46,13 +47,13 @@ require (
go.opentelemetry.io/otel/sdk v1.21.0
go.opentelemetry.io/otel/sdk/metric v1.21.0
go.opentelemetry.io/otel/trace v1.21.0
golang.org/x/sync v0.7.0
golang.org/x/sys v0.22.0
golang.org/x/term v0.20.0
golang.org/x/text v0.15.0
golang.org/x/sync v0.8.0
golang.org/x/sys v0.24.0
golang.org/x/term v0.23.0
golang.org/x/text v0.17.0
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.5.1
tags.cncf.io/container-device-interface v0.7.2
tags.cncf.io/container-device-interface v0.8.0
)
require (
@ -80,7 +81,6 @@ require (
github.com/moby/sys/symlink v0.3.0 // indirect
github.com/moby/sys/user v0.3.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
@ -94,11 +94,11 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/grpc v1.60.1 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/time v0.6.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/grpc v1.62.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)

View File

@ -1,5 +1,5 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
@ -105,8 +105,8 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -334,8 +334,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@ -351,8 +351,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -361,8 +361,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -383,26 +383,26 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -414,15 +414,15 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg=
google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic=
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f h1:2yNACc1O40tTnrsbk9Cv6oxiW8pxI/pXj0wRtdlYmgY=
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 h1:/jFB8jK5R3Sq3i/lmeZO0cATSzFfZaJq1J2Euan3XKU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA=
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU=
google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
@ -454,5 +454,5 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
tags.cncf.io/container-device-interface v0.7.2 h1:MLqGnWfOr1wB7m08ieI4YJ3IoLKKozEnnNYBtacDPQU=
tags.cncf.io/container-device-interface v0.7.2/go.mod h1:Xb1PvXv2BhfNb3tla4r9JL129ck1Lxv9KuU6eVOfKto=
tags.cncf.io/container-device-interface v0.8.0 h1:8bCFo/g9WODjWx3m6EYl3GfUG31eKJbaggyBDxEldRc=
tags.cncf.io/container-device-interface v0.8.0/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y=

View File

@ -13,6 +13,9 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Golang/Intellij
.idea
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/

View File

@ -44,13 +44,21 @@ Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the
## Status
It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, Microsoft, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
Mergo is stable and frozen, ready for production. Check a short list of the projects using at large scale it [here](https://github.com/imdario/mergo#mergo-in-the-wild).
No new features are accepted. They will be considered for a future v2 that improves the implementation and fixes bugs for corner cases.
### Important notes
#### 1.0.0
In [1.0.0](//github.com/imdario/mergo/releases/tag/1.0.0) Mergo moves to a vanity URL `dario.cat/mergo`.
In [1.0.0](//github.com/imdario/mergo/releases/tag/1.0.0) Mergo moves to a vanity URL `dario.cat/mergo`. No more v1 versions will be released.
If the vanity URL is causing issues in your project due to a dependency pulling Mergo - it isn't a direct dependency in your project - it is recommended to use [replace](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) to pin the version to the last one with the old import URL:
```
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16
```
#### 0.3.9
@ -64,55 +72,24 @@ If you were using Mergo before April 6th, 2015, please check your project works
If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
<a href='https://ko-fi.com/B0B58839' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
<a href="https://liberapay.com/dario/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a>
<a href='https://github.com/sponsors/imdario' target='_blank'><img alt="Become my sponsor" src="https://img.shields.io/github/sponsors/imdario?style=for-the-badge" /></a>
### Mergo in the wild
- [moby/moby](https://github.com/moby/moby)
- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
- [vmware/dispatch](https://github.com/vmware/dispatch)
- [Shopify/themekit](https://github.com/Shopify/themekit)
- [imdario/zas](https://github.com/imdario/zas)
- [matcornic/hermes](https://github.com/matcornic/hermes)
- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go)
- [kataras/iris](https://github.com/kataras/iris)
- [michaelsauter/crane](https://github.com/michaelsauter/crane)
- [go-task/task](https://github.com/go-task/task)
- [sensu/uchiwa](https://github.com/sensu/uchiwa)
- [ory/hydra](https://github.com/ory/hydra)
- [sisatech/vcli](https://github.com/sisatech/vcli)
- [dairycart/dairycart](https://github.com/dairycart/dairycart)
- [projectcalico/felix](https://github.com/projectcalico/felix)
- [resin-os/balena](https://github.com/resin-os/balena)
- [go-kivik/kivik](https://github.com/go-kivik/kivik)
- [Telefonica/govice](https://github.com/Telefonica/govice)
- [supergiant/supergiant](supergiant/supergiant)
- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce)
- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy)
- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel)
- [EagerIO/Stout](https://github.com/EagerIO/Stout)
- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api)
- [russross/canvasassignments](https://github.com/russross/canvasassignments)
- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api)
- [casualjim/exeggutor](https://github.com/casualjim/exeggutor)
- [divshot/gitling](https://github.com/divshot/gitling)
- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl)
- [andrerocker/deploy42](https://github.com/andrerocker/deploy42)
- [elwinar/rambler](https://github.com/elwinar/rambler)
- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman)
- [jfbus/impressionist](https://github.com/jfbus/impressionist)
- [Jmeyering/zealot](https://github.com/Jmeyering/zealot)
- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host)
- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go)
- [thoas/picfit](https://github.com/thoas/picfit)
- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
- [jnuthong/item_search](https://github.com/jnuthong/item_search)
- [bukalapak/snowboard](https://github.com/bukalapak/snowboard)
- [containerssh/containerssh](https://github.com/containerssh/containerssh)
- [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
- [tjpnz/structbot](https://github.com/tjpnz/structbot)
Mergo is used by [thousands](https://deps.dev/go/dario.cat%2Fmergo/v1.0.0/dependents) [of](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.16/dependents) [projects](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.12), including:
* [containerd/containerd](https://github.com/containerd/containerd)
* [datadog/datadog-agent](https://github.com/datadog/datadog-agent)
* [docker/cli/](https://github.com/docker/cli/)
* [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
* [go-micro/go-micro](https://github.com/go-micro/go-micro)
* [grafana/loki](https://github.com/grafana/loki)
* [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
* [masterminds/sprig](github.com/Masterminds/sprig)
* [moby/moby](https://github.com/moby/moby)
* [slackhq/nebula](https://github.com/slackhq/nebula)
* [volcano-sh/volcano](https://github.com/volcano-sh/volcano)
## Install
@ -141,6 +118,39 @@ if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
}
```
If you need to override pointers, so the source pointer's value is assigned to the destination's pointer, you must use `WithoutDereference`:
```go
package main
import (
"fmt"
"dario.cat/mergo"
)
type Foo struct {
A *string
B int64
}
func main() {
first := "first"
second := "second"
src := Foo{
A: &first,
B: 2,
}
dest := Foo{
A: &second,
B: 1,
}
mergo.Merge(&dest, src, mergo.WithOverride, mergo.WithoutDereference)
}
```
Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field.
```go

View File

@ -58,7 +58,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf
}
fieldName := field.Name
fieldName = changeInitialCase(fieldName, unicode.ToLower)
if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v), !config.ShouldNotDereference) || overwrite) {
if _, ok := dstMap[fieldName]; !ok || (!isEmptyValue(reflect.ValueOf(src.Field(i).Interface()), !config.ShouldNotDereference) && overwrite) || config.overwriteWithEmptyValue {
dstMap[fieldName] = src.Field(i).Interface()
}
}

View File

@ -269,7 +269,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
return
}
} else {
} else if src.Elem().Kind() != reflect.Struct {
if overwriteWithEmptySrc || (overwrite && !src.IsNil()) || dst.IsNil() {
dst.Set(src)
}

View File

@ -1,531 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package jsonpb
import (
"encoding/json"
"errors"
"fmt"
"io"
"math"
"reflect"
"strconv"
"strings"
"time"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson"
protoV2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
const wrapJSONUnmarshalV2 = false
// UnmarshalNext unmarshals the next JSON object from d into m.
func UnmarshalNext(d *json.Decoder, m proto.Message) error {
return new(Unmarshaler).UnmarshalNext(d, m)
}
// Unmarshal unmarshals a JSON object from r into m.
func Unmarshal(r io.Reader, m proto.Message) error {
return new(Unmarshaler).Unmarshal(r, m)
}
// UnmarshalString unmarshals a JSON object from s into m.
func UnmarshalString(s string, m proto.Message) error {
return new(Unmarshaler).Unmarshal(strings.NewReader(s), m)
}
// Unmarshaler is a configurable object for converting from a JSON
// representation to a protocol buffer object.
type Unmarshaler struct {
// AllowUnknownFields specifies whether to allow messages to contain
// unknown JSON fields, as opposed to failing to unmarshal.
AllowUnknownFields bool
// AnyResolver is used to resolve the google.protobuf.Any well-known type.
// If unset, the global registry is used by default.
AnyResolver AnyResolver
}
// JSONPBUnmarshaler is implemented by protobuf messages that customize the way
// they are unmarshaled from JSON. Messages that implement this should also
// implement JSONPBMarshaler so that the custom format can be produced.
//
// The JSON unmarshaling must follow the JSON to proto specification:
//
// https://developers.google.com/protocol-buffers/docs/proto3#json
//
// Deprecated: Custom types should implement protobuf reflection instead.
type JSONPBUnmarshaler interface {
UnmarshalJSONPB(*Unmarshaler, []byte) error
}
// Unmarshal unmarshals a JSON object from r into m.
func (u *Unmarshaler) Unmarshal(r io.Reader, m proto.Message) error {
return u.UnmarshalNext(json.NewDecoder(r), m)
}
// UnmarshalNext unmarshals the next JSON object from d into m.
func (u *Unmarshaler) UnmarshalNext(d *json.Decoder, m proto.Message) error {
if m == nil {
return errors.New("invalid nil message")
}
// Parse the next JSON object from the stream.
raw := json.RawMessage{}
if err := d.Decode(&raw); err != nil {
return err
}
// Check for custom unmarshalers first since they may not properly
// implement protobuf reflection that the logic below relies on.
if jsu, ok := m.(JSONPBUnmarshaler); ok {
return jsu.UnmarshalJSONPB(u, raw)
}
mr := proto.MessageReflect(m)
// NOTE: For historical reasons, a top-level null is treated as a noop.
// This is incorrect, but kept for compatibility.
if string(raw) == "null" && mr.Descriptor().FullName() != "google.protobuf.Value" {
return nil
}
if wrapJSONUnmarshalV2 {
// NOTE: If input message is non-empty, we need to preserve merge semantics
// of the old jsonpb implementation. These semantics are not supported by
// the protobuf JSON specification.
isEmpty := true
mr.Range(func(protoreflect.FieldDescriptor, protoreflect.Value) bool {
isEmpty = false // at least one iteration implies non-empty
return false
})
if !isEmpty {
// Perform unmarshaling into a newly allocated, empty message.
mr = mr.New()
// Use a defer to copy all unmarshaled fields into the original message.
dst := proto.MessageReflect(m)
defer mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
dst.Set(fd, v)
return true
})
}
// Unmarshal using the v2 JSON unmarshaler.
opts := protojson.UnmarshalOptions{
DiscardUnknown: u.AllowUnknownFields,
}
if u.AnyResolver != nil {
opts.Resolver = anyResolver{u.AnyResolver}
}
return opts.Unmarshal(raw, mr.Interface())
} else {
if err := u.unmarshalMessage(mr, raw); err != nil {
return err
}
return protoV2.CheckInitialized(mr.Interface())
}
}
func (u *Unmarshaler) unmarshalMessage(m protoreflect.Message, in []byte) error {
md := m.Descriptor()
fds := md.Fields()
if jsu, ok := proto.MessageV1(m.Interface()).(JSONPBUnmarshaler); ok {
return jsu.UnmarshalJSONPB(u, in)
}
if string(in) == "null" && md.FullName() != "google.protobuf.Value" {
return nil
}
switch wellKnownType(md.FullName()) {
case "Any":
var jsonObject map[string]json.RawMessage
if err := json.Unmarshal(in, &jsonObject); err != nil {
return err
}
rawTypeURL, ok := jsonObject["@type"]
if !ok {
return errors.New("Any JSON doesn't have '@type'")
}
typeURL, err := unquoteString(string(rawTypeURL))
if err != nil {
return fmt.Errorf("can't unmarshal Any's '@type': %q", rawTypeURL)
}
m.Set(fds.ByNumber(1), protoreflect.ValueOfString(typeURL))
var m2 protoreflect.Message
if u.AnyResolver != nil {
mi, err := u.AnyResolver.Resolve(typeURL)
if err != nil {
return err
}
m2 = proto.MessageReflect(mi)
} else {
mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL)
if err != nil {
if err == protoregistry.NotFound {
return fmt.Errorf("could not resolve Any message type: %v", typeURL)
}
return err
}
m2 = mt.New()
}
if wellKnownType(m2.Descriptor().FullName()) != "" {
rawValue, ok := jsonObject["value"]
if !ok {
return errors.New("Any JSON doesn't have 'value'")
}
if err := u.unmarshalMessage(m2, rawValue); err != nil {
return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err)
}
} else {
delete(jsonObject, "@type")
rawJSON, err := json.Marshal(jsonObject)
if err != nil {
return fmt.Errorf("can't generate JSON for Any's nested proto to be unmarshaled: %v", err)
}
if err = u.unmarshalMessage(m2, rawJSON); err != nil {
return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err)
}
}
rawWire, err := protoV2.Marshal(m2.Interface())
if err != nil {
return fmt.Errorf("can't marshal proto %v into Any.Value: %v", typeURL, err)
}
m.Set(fds.ByNumber(2), protoreflect.ValueOfBytes(rawWire))
return nil
case "BoolValue", "BytesValue", "StringValue",
"Int32Value", "UInt32Value", "FloatValue",
"Int64Value", "UInt64Value", "DoubleValue":
fd := fds.ByNumber(1)
v, err := u.unmarshalValue(m.NewField(fd), in, fd)
if err != nil {
return err
}
m.Set(fd, v)
return nil
case "Duration":
v, err := unquoteString(string(in))
if err != nil {
return err
}
d, err := time.ParseDuration(v)
if err != nil {
return fmt.Errorf("bad Duration: %v", err)
}
sec := d.Nanoseconds() / 1e9
nsec := d.Nanoseconds() % 1e9
m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec)))
m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec)))
return nil
case "Timestamp":
v, err := unquoteString(string(in))
if err != nil {
return err
}
t, err := time.Parse(time.RFC3339Nano, v)
if err != nil {
return fmt.Errorf("bad Timestamp: %v", err)
}
sec := t.Unix()
nsec := t.Nanosecond()
m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec)))
m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec)))
return nil
case "Value":
switch {
case string(in) == "null":
m.Set(fds.ByNumber(1), protoreflect.ValueOfEnum(0))
case string(in) == "true":
m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(true))
case string(in) == "false":
m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(false))
case hasPrefixAndSuffix('"', in, '"'):
s, err := unquoteString(string(in))
if err != nil {
return fmt.Errorf("unrecognized type for Value %q", in)
}
m.Set(fds.ByNumber(3), protoreflect.ValueOfString(s))
case hasPrefixAndSuffix('[', in, ']'):
v := m.Mutable(fds.ByNumber(6))
return u.unmarshalMessage(v.Message(), in)
case hasPrefixAndSuffix('{', in, '}'):
v := m.Mutable(fds.ByNumber(5))
return u.unmarshalMessage(v.Message(), in)
default:
f, err := strconv.ParseFloat(string(in), 0)
if err != nil {
return fmt.Errorf("unrecognized type for Value %q", in)
}
m.Set(fds.ByNumber(2), protoreflect.ValueOfFloat64(f))
}
return nil
case "ListValue":
var jsonArray []json.RawMessage
if err := json.Unmarshal(in, &jsonArray); err != nil {
return fmt.Errorf("bad ListValue: %v", err)
}
lv := m.Mutable(fds.ByNumber(1)).List()
for _, raw := range jsonArray {
ve := lv.NewElement()
if err := u.unmarshalMessage(ve.Message(), raw); err != nil {
return err
}
lv.Append(ve)
}
return nil
case "Struct":
var jsonObject map[string]json.RawMessage
if err := json.Unmarshal(in, &jsonObject); err != nil {
return fmt.Errorf("bad StructValue: %v", err)
}
mv := m.Mutable(fds.ByNumber(1)).Map()
for key, raw := range jsonObject {
kv := protoreflect.ValueOf(key).MapKey()
vv := mv.NewValue()
if err := u.unmarshalMessage(vv.Message(), raw); err != nil {
return fmt.Errorf("bad value in StructValue for key %q: %v", key, err)
}
mv.Set(kv, vv)
}
return nil
}
var jsonObject map[string]json.RawMessage
if err := json.Unmarshal(in, &jsonObject); err != nil {
return err
}
// Handle known fields.
for i := 0; i < fds.Len(); i++ {
fd := fds.Get(i)
if fd.IsWeak() && fd.Message().IsPlaceholder() {
continue // weak reference is not linked in
}
// Search for any raw JSON value associated with this field.
var raw json.RawMessage
name := string(fd.Name())
if fd.Kind() == protoreflect.GroupKind {
name = string(fd.Message().Name())
}
if v, ok := jsonObject[name]; ok {
delete(jsonObject, name)
raw = v
}
name = string(fd.JSONName())
if v, ok := jsonObject[name]; ok {
delete(jsonObject, name)
raw = v
}
field := m.NewField(fd)
// Unmarshal the field value.
if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) {
continue
}
v, err := u.unmarshalValue(field, raw, fd)
if err != nil {
return err
}
m.Set(fd, v)
}
// Handle extension fields.
for name, raw := range jsonObject {
if !strings.HasPrefix(name, "[") || !strings.HasSuffix(name, "]") {
continue
}
// Resolve the extension field by name.
xname := protoreflect.FullName(name[len("[") : len(name)-len("]")])
xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname)
if xt == nil && isMessageSet(md) {
xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension"))
}
if xt == nil {
continue
}
delete(jsonObject, name)
fd := xt.TypeDescriptor()
if fd.ContainingMessage().FullName() != m.Descriptor().FullName() {
return fmt.Errorf("extension field %q does not extend message %q", xname, m.Descriptor().FullName())
}
field := m.NewField(fd)
// Unmarshal the field value.
if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) {
continue
}
v, err := u.unmarshalValue(field, raw, fd)
if err != nil {
return err
}
m.Set(fd, v)
}
if !u.AllowUnknownFields && len(jsonObject) > 0 {
for name := range jsonObject {
return fmt.Errorf("unknown field %q in %v", name, md.FullName())
}
}
return nil
}
func isSingularWellKnownValue(fd protoreflect.FieldDescriptor) bool {
if fd.Cardinality() == protoreflect.Repeated {
return false
}
if md := fd.Message(); md != nil {
return md.FullName() == "google.protobuf.Value"
}
if ed := fd.Enum(); ed != nil {
return ed.FullName() == "google.protobuf.NullValue"
}
return false
}
func isSingularJSONPBUnmarshaler(v protoreflect.Value, fd protoreflect.FieldDescriptor) bool {
if fd.Message() != nil && fd.Cardinality() != protoreflect.Repeated {
_, ok := proto.MessageV1(v.Interface()).(JSONPBUnmarshaler)
return ok
}
return false
}
func (u *Unmarshaler) unmarshalValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
switch {
case fd.IsList():
var jsonArray []json.RawMessage
if err := json.Unmarshal(in, &jsonArray); err != nil {
return v, err
}
lv := v.List()
for _, raw := range jsonArray {
ve, err := u.unmarshalSingularValue(lv.NewElement(), raw, fd)
if err != nil {
return v, err
}
lv.Append(ve)
}
return v, nil
case fd.IsMap():
var jsonObject map[string]json.RawMessage
if err := json.Unmarshal(in, &jsonObject); err != nil {
return v, err
}
kfd := fd.MapKey()
vfd := fd.MapValue()
mv := v.Map()
for key, raw := range jsonObject {
var kv protoreflect.MapKey
if kfd.Kind() == protoreflect.StringKind {
kv = protoreflect.ValueOf(key).MapKey()
} else {
v, err := u.unmarshalSingularValue(kfd.Default(), []byte(key), kfd)
if err != nil {
return v, err
}
kv = v.MapKey()
}
vv, err := u.unmarshalSingularValue(mv.NewValue(), raw, vfd)
if err != nil {
return v, err
}
mv.Set(kv, vv)
}
return v, nil
default:
return u.unmarshalSingularValue(v, in, fd)
}
}
var nonFinite = map[string]float64{
`"NaN"`: math.NaN(),
`"Infinity"`: math.Inf(+1),
`"-Infinity"`: math.Inf(-1),
}
func (u *Unmarshaler) unmarshalSingularValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
switch fd.Kind() {
case protoreflect.BoolKind:
return unmarshalValue(in, new(bool))
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
return unmarshalValue(trimQuote(in), new(int32))
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
return unmarshalValue(trimQuote(in), new(int64))
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
return unmarshalValue(trimQuote(in), new(uint32))
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
return unmarshalValue(trimQuote(in), new(uint64))
case protoreflect.FloatKind:
if f, ok := nonFinite[string(in)]; ok {
return protoreflect.ValueOfFloat32(float32(f)), nil
}
return unmarshalValue(trimQuote(in), new(float32))
case protoreflect.DoubleKind:
if f, ok := nonFinite[string(in)]; ok {
return protoreflect.ValueOfFloat64(float64(f)), nil
}
return unmarshalValue(trimQuote(in), new(float64))
case protoreflect.StringKind:
return unmarshalValue(in, new(string))
case protoreflect.BytesKind:
return unmarshalValue(in, new([]byte))
case protoreflect.EnumKind:
if hasPrefixAndSuffix('"', in, '"') {
vd := fd.Enum().Values().ByName(protoreflect.Name(trimQuote(in)))
if vd == nil {
return v, fmt.Errorf("unknown value %q for enum %s", in, fd.Enum().FullName())
}
return protoreflect.ValueOfEnum(vd.Number()), nil
}
return unmarshalValue(in, new(protoreflect.EnumNumber))
case protoreflect.MessageKind, protoreflect.GroupKind:
err := u.unmarshalMessage(v.Message(), in)
return v, err
default:
panic(fmt.Sprintf("invalid kind %v", fd.Kind()))
}
}
func unmarshalValue(in []byte, v interface{}) (protoreflect.Value, error) {
err := json.Unmarshal(in, v)
return protoreflect.ValueOf(reflect.ValueOf(v).Elem().Interface()), err
}
func unquoteString(in string) (out string, err error) {
err = json.Unmarshal([]byte(in), &out)
return out, err
}
func hasPrefixAndSuffix(prefix byte, in []byte, suffix byte) bool {
if len(in) >= 2 && in[0] == prefix && in[len(in)-1] == suffix {
return true
}
return false
}
// trimQuote is like unquoteString but simply strips surrounding quotes.
// This is incorrect, but is behavior done by the legacy implementation.
func trimQuote(in []byte) []byte {
if len(in) >= 2 && in[0] == '"' && in[len(in)-1] == '"' {
in = in[1 : len(in)-1]
}
return in
}

View File

@ -1,560 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package jsonpb
import (
"encoding/json"
"errors"
"fmt"
"io"
"math"
"reflect"
"sort"
"strconv"
"strings"
"time"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson"
protoV2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
const wrapJSONMarshalV2 = false
// Marshaler is a configurable object for marshaling protocol buffer messages
// to the specified JSON representation.
type Marshaler struct {
// OrigName specifies whether to use the original protobuf name for fields.
OrigName bool
// EnumsAsInts specifies whether to render enum values as integers,
// as opposed to string values.
EnumsAsInts bool
// EmitDefaults specifies whether to render fields with zero values.
EmitDefaults bool
// Indent controls whether the output is compact or not.
// If empty, the output is compact JSON. Otherwise, every JSON object
// entry and JSON array value will be on its own line.
// Each line will be preceded by repeated copies of Indent, where the
// number of copies is the current indentation depth.
Indent string
// AnyResolver is used to resolve the google.protobuf.Any well-known type.
// If unset, the global registry is used by default.
AnyResolver AnyResolver
}
// JSONPBMarshaler is implemented by protobuf messages that customize the
// way they are marshaled to JSON. Messages that implement this should also
// implement JSONPBUnmarshaler so that the custom format can be parsed.
//
// The JSON marshaling must follow the proto to JSON specification:
//
// https://developers.google.com/protocol-buffers/docs/proto3#json
//
// Deprecated: Custom types should implement protobuf reflection instead.
type JSONPBMarshaler interface {
MarshalJSONPB(*Marshaler) ([]byte, error)
}
// Marshal serializes a protobuf message as JSON into w.
func (jm *Marshaler) Marshal(w io.Writer, m proto.Message) error {
b, err := jm.marshal(m)
if len(b) > 0 {
if _, err := w.Write(b); err != nil {
return err
}
}
return err
}
// MarshalToString serializes a protobuf message as JSON in string form.
func (jm *Marshaler) MarshalToString(m proto.Message) (string, error) {
b, err := jm.marshal(m)
if err != nil {
return "", err
}
return string(b), nil
}
func (jm *Marshaler) marshal(m proto.Message) ([]byte, error) {
v := reflect.ValueOf(m)
if m == nil || (v.Kind() == reflect.Ptr && v.IsNil()) {
return nil, errors.New("Marshal called with nil")
}
// Check for custom marshalers first since they may not properly
// implement protobuf reflection that the logic below relies on.
if jsm, ok := m.(JSONPBMarshaler); ok {
return jsm.MarshalJSONPB(jm)
}
if wrapJSONMarshalV2 {
opts := protojson.MarshalOptions{
UseProtoNames: jm.OrigName,
UseEnumNumbers: jm.EnumsAsInts,
EmitUnpopulated: jm.EmitDefaults,
Indent: jm.Indent,
}
if jm.AnyResolver != nil {
opts.Resolver = anyResolver{jm.AnyResolver}
}
return opts.Marshal(proto.MessageReflect(m).Interface())
} else {
// Check for unpopulated required fields first.
m2 := proto.MessageReflect(m)
if err := protoV2.CheckInitialized(m2.Interface()); err != nil {
return nil, err
}
w := jsonWriter{Marshaler: jm}
err := w.marshalMessage(m2, "", "")
return w.buf, err
}
}
type jsonWriter struct {
*Marshaler
buf []byte
}
func (w *jsonWriter) write(s string) {
w.buf = append(w.buf, s...)
}
func (w *jsonWriter) marshalMessage(m protoreflect.Message, indent, typeURL string) error {
if jsm, ok := proto.MessageV1(m.Interface()).(JSONPBMarshaler); ok {
b, err := jsm.MarshalJSONPB(w.Marshaler)
if err != nil {
return err
}
if typeURL != "" {
// we are marshaling this object to an Any type
var js map[string]*json.RawMessage
if err = json.Unmarshal(b, &js); err != nil {
return fmt.Errorf("type %T produced invalid JSON: %v", m.Interface(), err)
}
turl, err := json.Marshal(typeURL)
if err != nil {
return fmt.Errorf("failed to marshal type URL %q to JSON: %v", typeURL, err)
}
js["@type"] = (*json.RawMessage)(&turl)
if b, err = json.Marshal(js); err != nil {
return err
}
}
w.write(string(b))
return nil
}
md := m.Descriptor()
fds := md.Fields()
// Handle well-known types.
const secondInNanos = int64(time.Second / time.Nanosecond)
switch wellKnownType(md.FullName()) {
case "Any":
return w.marshalAny(m, indent)
case "BoolValue", "BytesValue", "StringValue",
"Int32Value", "UInt32Value", "FloatValue",
"Int64Value", "UInt64Value", "DoubleValue":
fd := fds.ByNumber(1)
return w.marshalValue(fd, m.Get(fd), indent)
case "Duration":
const maxSecondsInDuration = 315576000000
// "Generated output always contains 0, 3, 6, or 9 fractional digits,
// depending on required precision."
s := m.Get(fds.ByNumber(1)).Int()
ns := m.Get(fds.ByNumber(2)).Int()
if s < -maxSecondsInDuration || s > maxSecondsInDuration {
return fmt.Errorf("seconds out of range %v", s)
}
if ns <= -secondInNanos || ns >= secondInNanos {
return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos)
}
if (s > 0 && ns < 0) || (s < 0 && ns > 0) {
return errors.New("signs of seconds and nanos do not match")
}
var sign string
if s < 0 || ns < 0 {
sign, s, ns = "-", -1*s, -1*ns
}
x := fmt.Sprintf("%s%d.%09d", sign, s, ns)
x = strings.TrimSuffix(x, "000")
x = strings.TrimSuffix(x, "000")
x = strings.TrimSuffix(x, ".000")
w.write(fmt.Sprintf(`"%vs"`, x))
return nil
case "Timestamp":
// "RFC 3339, where generated output will always be Z-normalized
// and uses 0, 3, 6 or 9 fractional digits."
s := m.Get(fds.ByNumber(1)).Int()
ns := m.Get(fds.ByNumber(2)).Int()
if ns < 0 || ns >= secondInNanos {
return fmt.Errorf("ns out of range [0, %v)", secondInNanos)
}
t := time.Unix(s, ns).UTC()
// time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits).
x := t.Format("2006-01-02T15:04:05.000000000")
x = strings.TrimSuffix(x, "000")
x = strings.TrimSuffix(x, "000")
x = strings.TrimSuffix(x, ".000")
w.write(fmt.Sprintf(`"%vZ"`, x))
return nil
case "Value":
// JSON value; which is a null, number, string, bool, object, or array.
od := md.Oneofs().Get(0)
fd := m.WhichOneof(od)
if fd == nil {
return errors.New("nil Value")
}
return w.marshalValue(fd, m.Get(fd), indent)
case "Struct", "ListValue":
// JSON object or array.
fd := fds.ByNumber(1)
return w.marshalValue(fd, m.Get(fd), indent)
}
w.write("{")
if w.Indent != "" {
w.write("\n")
}
firstField := true
if typeURL != "" {
if err := w.marshalTypeURL(indent, typeURL); err != nil {
return err
}
firstField = false
}
for i := 0; i < fds.Len(); {
fd := fds.Get(i)
if od := fd.ContainingOneof(); od != nil {
fd = m.WhichOneof(od)
i += od.Fields().Len()
if fd == nil {
continue
}
} else {
i++
}
v := m.Get(fd)
if !m.Has(fd) {
if !w.EmitDefaults || fd.ContainingOneof() != nil {
continue
}
if fd.Cardinality() != protoreflect.Repeated && (fd.Message() != nil || fd.Syntax() == protoreflect.Proto2) {
v = protoreflect.Value{} // use "null" for singular messages or proto2 scalars
}
}
if !firstField {
w.writeComma()
}
if err := w.marshalField(fd, v, indent); err != nil {
return err
}
firstField = false
}
// Handle proto2 extensions.
if md.ExtensionRanges().Len() > 0 {
// Collect a sorted list of all extension descriptor and values.
type ext struct {
desc protoreflect.FieldDescriptor
val protoreflect.Value
}
var exts []ext
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
if fd.IsExtension() {
exts = append(exts, ext{fd, v})
}
return true
})
sort.Slice(exts, func(i, j int) bool {
return exts[i].desc.Number() < exts[j].desc.Number()
})
for _, ext := range exts {
if !firstField {
w.writeComma()
}
if err := w.marshalField(ext.desc, ext.val, indent); err != nil {
return err
}
firstField = false
}
}
if w.Indent != "" {
w.write("\n")
w.write(indent)
}
w.write("}")
return nil
}
func (w *jsonWriter) writeComma() {
if w.Indent != "" {
w.write(",\n")
} else {
w.write(",")
}
}
func (w *jsonWriter) marshalAny(m protoreflect.Message, indent string) error {
// "If the Any contains a value that has a special JSON mapping,
// it will be converted as follows: {"@type": xxx, "value": yyy}.
// Otherwise, the value will be converted into a JSON object,
// and the "@type" field will be inserted to indicate the actual data type."
md := m.Descriptor()
typeURL := m.Get(md.Fields().ByNumber(1)).String()
rawVal := m.Get(md.Fields().ByNumber(2)).Bytes()
var m2 protoreflect.Message
if w.AnyResolver != nil {
mi, err := w.AnyResolver.Resolve(typeURL)
if err != nil {
return err
}
m2 = proto.MessageReflect(mi)
} else {
mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL)
if err != nil {
return err
}
m2 = mt.New()
}
if err := protoV2.Unmarshal(rawVal, m2.Interface()); err != nil {
return err
}
if wellKnownType(m2.Descriptor().FullName()) == "" {
return w.marshalMessage(m2, indent, typeURL)
}
w.write("{")
if w.Indent != "" {
w.write("\n")
}
if err := w.marshalTypeURL(indent, typeURL); err != nil {
return err
}
w.writeComma()
if w.Indent != "" {
w.write(indent)
w.write(w.Indent)
w.write(`"value": `)
} else {
w.write(`"value":`)
}
if err := w.marshalMessage(m2, indent+w.Indent, ""); err != nil {
return err
}
if w.Indent != "" {
w.write("\n")
w.write(indent)
}
w.write("}")
return nil
}
func (w *jsonWriter) marshalTypeURL(indent, typeURL string) error {
if w.Indent != "" {
w.write(indent)
w.write(w.Indent)
}
w.write(`"@type":`)
if w.Indent != "" {
w.write(" ")
}
b, err := json.Marshal(typeURL)
if err != nil {
return err
}
w.write(string(b))
return nil
}
// marshalField writes field description and value to the Writer.
func (w *jsonWriter) marshalField(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
if w.Indent != "" {
w.write(indent)
w.write(w.Indent)
}
w.write(`"`)
switch {
case fd.IsExtension():
// For message set, use the fname of the message as the extension name.
name := string(fd.FullName())
if isMessageSet(fd.ContainingMessage()) {
name = strings.TrimSuffix(name, ".message_set_extension")
}
w.write("[" + name + "]")
case w.OrigName:
name := string(fd.Name())
if fd.Kind() == protoreflect.GroupKind {
name = string(fd.Message().Name())
}
w.write(name)
default:
w.write(string(fd.JSONName()))
}
w.write(`":`)
if w.Indent != "" {
w.write(" ")
}
return w.marshalValue(fd, v, indent)
}
func (w *jsonWriter) marshalValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
switch {
case fd.IsList():
w.write("[")
comma := ""
lv := v.List()
for i := 0; i < lv.Len(); i++ {
w.write(comma)
if w.Indent != "" {
w.write("\n")
w.write(indent)
w.write(w.Indent)
w.write(w.Indent)
}
if err := w.marshalSingularValue(fd, lv.Get(i), indent+w.Indent); err != nil {
return err
}
comma = ","
}
if w.Indent != "" {
w.write("\n")
w.write(indent)
w.write(w.Indent)
}
w.write("]")
return nil
case fd.IsMap():
kfd := fd.MapKey()
vfd := fd.MapValue()
mv := v.Map()
// Collect a sorted list of all map keys and values.
type entry struct{ key, val protoreflect.Value }
var entries []entry
mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
entries = append(entries, entry{k.Value(), v})
return true
})
sort.Slice(entries, func(i, j int) bool {
switch kfd.Kind() {
case protoreflect.BoolKind:
return !entries[i].key.Bool() && entries[j].key.Bool()
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
return entries[i].key.Int() < entries[j].key.Int()
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
return entries[i].key.Uint() < entries[j].key.Uint()
case protoreflect.StringKind:
return entries[i].key.String() < entries[j].key.String()
default:
panic("invalid kind")
}
})
w.write(`{`)
comma := ""
for _, entry := range entries {
w.write(comma)
if w.Indent != "" {
w.write("\n")
w.write(indent)
w.write(w.Indent)
w.write(w.Indent)
}
s := fmt.Sprint(entry.key.Interface())
b, err := json.Marshal(s)
if err != nil {
return err
}
w.write(string(b))
w.write(`:`)
if w.Indent != "" {
w.write(` `)
}
if err := w.marshalSingularValue(vfd, entry.val, indent+w.Indent); err != nil {
return err
}
comma = ","
}
if w.Indent != "" {
w.write("\n")
w.write(indent)
w.write(w.Indent)
}
w.write(`}`)
return nil
default:
return w.marshalSingularValue(fd, v, indent)
}
}
func (w *jsonWriter) marshalSingularValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
switch {
case !v.IsValid():
w.write("null")
return nil
case fd.Message() != nil:
return w.marshalMessage(v.Message(), indent+w.Indent, "")
case fd.Enum() != nil:
if fd.Enum().FullName() == "google.protobuf.NullValue" {
w.write("null")
return nil
}
vd := fd.Enum().Values().ByNumber(v.Enum())
if vd == nil || w.EnumsAsInts {
w.write(strconv.Itoa(int(v.Enum())))
} else {
w.write(`"` + string(vd.Name()) + `"`)
}
return nil
default:
switch v.Interface().(type) {
case float32, float64:
switch {
case math.IsInf(v.Float(), +1):
w.write(`"Infinity"`)
return nil
case math.IsInf(v.Float(), -1):
w.write(`"-Infinity"`)
return nil
case math.IsNaN(v.Float()):
w.write(`"NaN"`)
return nil
}
case int64, uint64:
w.write(fmt.Sprintf(`"%d"`, v.Interface()))
return nil
}
b, err := json.Marshal(v.Interface())
if err != nil {
return err
}
w.write(string(b))
return nil
}
}

View File

@ -1,69 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package jsonpb provides functionality to marshal and unmarshal between a
// protocol buffer message and JSON. It follows the specification at
// https://developers.google.com/protocol-buffers/docs/proto3#json.
//
// Do not rely on the default behavior of the standard encoding/json package
// when called on generated message types as it does not operate correctly.
//
// Deprecated: Use the "google.golang.org/protobuf/encoding/protojson"
// package instead.
package jsonpb
import (
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/runtime/protoimpl"
)
// AnyResolver takes a type URL, present in an Any message,
// and resolves it into an instance of the associated message.
type AnyResolver interface {
Resolve(typeURL string) (proto.Message, error)
}
type anyResolver struct{ AnyResolver }
func (r anyResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) {
return r.FindMessageByURL(string(message))
}
func (r anyResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) {
m, err := r.Resolve(url)
if err != nil {
return nil, err
}
return protoimpl.X.MessageTypeOf(m), nil
}
func (r anyResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {
return protoregistry.GlobalTypes.FindExtensionByName(field)
}
func (r anyResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {
return protoregistry.GlobalTypes.FindExtensionByNumber(message, field)
}
func wellKnownType(s protoreflect.FullName) string {
if s.Parent() == "google.protobuf" {
switch s.Name() {
case "Empty", "Any",
"BoolValue", "BytesValue", "StringValue",
"Int32Value", "UInt32Value", "FloatValue",
"Int64Value", "UInt64Value", "DoubleValue",
"Duration", "Timestamp",
"NullValue", "Struct", "Value", "ListValue":
return string(s.Name())
}
}
return ""
}
func isMessageSet(md protoreflect.MessageDescriptor) bool {
ms, ok := md.(interface{ IsMessageSet() bool })
return ok && ms.IsMessageSet()
}

View File

@ -1,180 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ptypes
import (
"fmt"
"strings"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
anypb "github.com/golang/protobuf/ptypes/any"
)
const urlPrefix = "type.googleapis.com/"
// AnyMessageName returns the message name contained in an anypb.Any message.
// Most type assertions should use the Is function instead.
//
// Deprecated: Call the any.MessageName method instead.
func AnyMessageName(any *anypb.Any) (string, error) {
name, err := anyMessageName(any)
return string(name), err
}
func anyMessageName(any *anypb.Any) (protoreflect.FullName, error) {
if any == nil {
return "", fmt.Errorf("message is nil")
}
name := protoreflect.FullName(any.TypeUrl)
if i := strings.LastIndex(any.TypeUrl, "/"); i >= 0 {
name = name[i+len("/"):]
}
if !name.IsValid() {
return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl)
}
return name, nil
}
// MarshalAny marshals the given message m into an anypb.Any message.
//
// Deprecated: Call the anypb.New function instead.
func MarshalAny(m proto.Message) (*anypb.Any, error) {
switch dm := m.(type) {
case DynamicAny:
m = dm.Message
case *DynamicAny:
if dm == nil {
return nil, proto.ErrNil
}
m = dm.Message
}
b, err := proto.Marshal(m)
if err != nil {
return nil, err
}
return &anypb.Any{TypeUrl: urlPrefix + proto.MessageName(m), Value: b}, nil
}
// Empty returns a new message of the type specified in an anypb.Any message.
// It returns protoregistry.NotFound if the corresponding message type could not
// be resolved in the global registry.
//
// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead
// to resolve the message name and create a new instance of it.
func Empty(any *anypb.Any) (proto.Message, error) {
name, err := anyMessageName(any)
if err != nil {
return nil, err
}
mt, err := protoregistry.GlobalTypes.FindMessageByName(name)
if err != nil {
return nil, err
}
return proto.MessageV1(mt.New().Interface()), nil
}
// UnmarshalAny unmarshals the encoded value contained in the anypb.Any message
// into the provided message m. It returns an error if the target message
// does not match the type in the Any message or if an unmarshal error occurs.
//
// The target message m may be a *DynamicAny message. If the underlying message
// type could not be resolved, then this returns protoregistry.NotFound.
//
// Deprecated: Call the any.UnmarshalTo method instead.
func UnmarshalAny(any *anypb.Any, m proto.Message) error {
if dm, ok := m.(*DynamicAny); ok {
if dm.Message == nil {
var err error
dm.Message, err = Empty(any)
if err != nil {
return err
}
}
m = dm.Message
}
anyName, err := AnyMessageName(any)
if err != nil {
return err
}
msgName := proto.MessageName(m)
if anyName != msgName {
return fmt.Errorf("mismatched message type: got %q want %q", anyName, msgName)
}
return proto.Unmarshal(any.Value, m)
}
// Is reports whether the Any message contains a message of the specified type.
//
// Deprecated: Call the any.MessageIs method instead.
func Is(any *anypb.Any, m proto.Message) bool {
if any == nil || m == nil {
return false
}
name := proto.MessageName(m)
if !strings.HasSuffix(any.TypeUrl, name) {
return false
}
return len(any.TypeUrl) == len(name) || any.TypeUrl[len(any.TypeUrl)-len(name)-1] == '/'
}
// DynamicAny is a value that can be passed to UnmarshalAny to automatically
// allocate a proto.Message for the type specified in an anypb.Any message.
// The allocated message is stored in the embedded proto.Message.
//
// Example:
//
// var x ptypes.DynamicAny
// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... }
// fmt.Printf("unmarshaled message: %v", x.Message)
//
// Deprecated: Use the any.UnmarshalNew method instead to unmarshal
// the any message contents into a new instance of the underlying message.
type DynamicAny struct{ proto.Message }
func (m DynamicAny) String() string {
if m.Message == nil {
return "<nil>"
}
return m.Message.String()
}
func (m DynamicAny) Reset() {
if m.Message == nil {
return
}
m.Message.Reset()
}
func (m DynamicAny) ProtoMessage() {
return
}
func (m DynamicAny) ProtoReflect() protoreflect.Message {
if m.Message == nil {
return nil
}
return dynamicAny{proto.MessageReflect(m.Message)}
}
type dynamicAny struct{ protoreflect.Message }
func (m dynamicAny) Type() protoreflect.MessageType {
return dynamicAnyType{m.Message.Type()}
}
func (m dynamicAny) New() protoreflect.Message {
return dynamicAnyType{m.Message.Type()}.New()
}
func (m dynamicAny) Interface() protoreflect.ProtoMessage {
return DynamicAny{proto.MessageV1(m.Message.Interface())}
}
type dynamicAnyType struct{ protoreflect.MessageType }
func (t dynamicAnyType) New() protoreflect.Message {
return dynamicAny{t.MessageType.New()}
}
func (t dynamicAnyType) Zero() protoreflect.Message {
return dynamicAny{t.MessageType.Zero()}
}

View File

@ -1,62 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: github.com/golang/protobuf/ptypes/any/any.proto
package any
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
anypb "google.golang.org/protobuf/types/known/anypb"
reflect "reflect"
)
// Symbols defined in public import of google/protobuf/any.proto.
type Any = anypb.Any
var File_github_com_golang_protobuf_ptypes_any_any_proto protoreflect.FileDescriptor
var file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = []byte{
0x0a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
0x70, 0x65, 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2b, 0x5a, 0x29,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65,
0x73, 0x2f, 0x61, 0x6e, 0x79, 0x3b, 0x61, 0x6e, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
var file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = []interface{}{}
var file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_github_com_golang_protobuf_ptypes_any_any_proto_init() }
func file_github_com_golang_protobuf_ptypes_any_any_proto_init() {
if File_github_com_golang_protobuf_ptypes_any_any_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes,
DependencyIndexes: file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs,
}.Build()
File_github_com_golang_protobuf_ptypes_any_any_proto = out.File
file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = nil
file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = nil
file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = nil
}

View File

@ -1,10 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package ptypes provides functionality for interacting with well-known types.
//
// Deprecated: Well-known types have specialized functionality directly
// injected into the generated packages for each message type.
// See the deprecation notice for each function for the suggested alternative.
package ptypes

View File

@ -1,76 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ptypes
import (
"errors"
"fmt"
"time"
durationpb "github.com/golang/protobuf/ptypes/duration"
)
// Range of google.protobuf.Duration as specified in duration.proto.
// This is about 10,000 years in seconds.
const (
maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
minSeconds = -maxSeconds
)
// Duration converts a durationpb.Duration to a time.Duration.
// Duration returns an error if dur is invalid or overflows a time.Duration.
//
// Deprecated: Call the dur.AsDuration and dur.CheckValid methods instead.
func Duration(dur *durationpb.Duration) (time.Duration, error) {
if err := validateDuration(dur); err != nil {
return 0, err
}
d := time.Duration(dur.Seconds) * time.Second
if int64(d/time.Second) != dur.Seconds {
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
}
if dur.Nanos != 0 {
d += time.Duration(dur.Nanos) * time.Nanosecond
if (d < 0) != (dur.Nanos < 0) {
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
}
}
return d, nil
}
// DurationProto converts a time.Duration to a durationpb.Duration.
//
// Deprecated: Call the durationpb.New function instead.
func DurationProto(d time.Duration) *durationpb.Duration {
nanos := d.Nanoseconds()
secs := nanos / 1e9
nanos -= secs * 1e9
return &durationpb.Duration{
Seconds: int64(secs),
Nanos: int32(nanos),
}
}
// validateDuration determines whether the durationpb.Duration is valid
// according to the definition in google/protobuf/duration.proto.
// A valid durpb.Duration may still be too large to fit into a time.Duration
// Note that the range of durationpb.Duration is about 10,000 years,
// while the range of time.Duration is about 290 years.
func validateDuration(dur *durationpb.Duration) error {
if dur == nil {
return errors.New("duration: nil Duration")
}
if dur.Seconds < minSeconds || dur.Seconds > maxSeconds {
return fmt.Errorf("duration: %v: seconds out of range", dur)
}
if dur.Nanos <= -1e9 || dur.Nanos >= 1e9 {
return fmt.Errorf("duration: %v: nanos out of range", dur)
}
// Seconds and Nanos must have the same sign, unless d.Nanos is zero.
if (dur.Seconds < 0 && dur.Nanos > 0) || (dur.Seconds > 0 && dur.Nanos < 0) {
return fmt.Errorf("duration: %v: seconds and nanos have different signs", dur)
}
return nil
}

View File

@ -1,63 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: github.com/golang/protobuf/ptypes/duration/duration.proto
package duration
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
durationpb "google.golang.org/protobuf/types/known/durationpb"
reflect "reflect"
)
// Symbols defined in public import of google/protobuf/duration.proto.
type Duration = durationpb.Duration
var File_github_com_golang_protobuf_ptypes_duration_duration_proto protoreflect.FileDescriptor
var file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = []byte{
0x0a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
0x70, 0x65, 0x73, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x75, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x35, 0x5a, 0x33, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73,
0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = []interface{}{}
var file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() }
func file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() {
if File_github_com_golang_protobuf_ptypes_duration_duration_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes,
DependencyIndexes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs,
}.Build()
File_github_com_golang_protobuf_ptypes_duration_duration_proto = out.File
file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = nil
file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = nil
file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = nil
}

View File

@ -1,112 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ptypes
import (
"errors"
"fmt"
"time"
timestamppb "github.com/golang/protobuf/ptypes/timestamp"
)
// Range of google.protobuf.Duration as specified in timestamp.proto.
const (
// Seconds field of the earliest valid Timestamp.
// This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
minValidSeconds = -62135596800
// Seconds field just after the latest valid Timestamp.
// This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
maxValidSeconds = 253402300800
)
// Timestamp converts a timestamppb.Timestamp to a time.Time.
// It returns an error if the argument is invalid.
//
// Unlike most Go functions, if Timestamp returns an error, the first return
// value is not the zero time.Time. Instead, it is the value obtained from the
// time.Unix function when passed the contents of the Timestamp, in the UTC
// locale. This may or may not be a meaningful time; many invalid Timestamps
// do map to valid time.Times.
//
// A nil Timestamp returns an error. The first return value in that case is
// undefined.
//
// Deprecated: Call the ts.AsTime and ts.CheckValid methods instead.
func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) {
// Don't return the zero value on error, because corresponds to a valid
// timestamp. Instead return whatever time.Unix gives us.
var t time.Time
if ts == nil {
t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
} else {
t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
}
return t, validateTimestamp(ts)
}
// TimestampNow returns a google.protobuf.Timestamp for the current time.
//
// Deprecated: Call the timestamppb.Now function instead.
func TimestampNow() *timestamppb.Timestamp {
ts, err := TimestampProto(time.Now())
if err != nil {
panic("ptypes: time.Now() out of Timestamp range")
}
return ts
}
// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
// It returns an error if the resulting Timestamp is invalid.
//
// Deprecated: Call the timestamppb.New function instead.
func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) {
ts := &timestamppb.Timestamp{
Seconds: t.Unix(),
Nanos: int32(t.Nanosecond()),
}
if err := validateTimestamp(ts); err != nil {
return nil, err
}
return ts, nil
}
// TimestampString returns the RFC 3339 string for valid Timestamps.
// For invalid Timestamps, it returns an error message in parentheses.
//
// Deprecated: Call the ts.AsTime method instead,
// followed by a call to the Format method on the time.Time value.
func TimestampString(ts *timestamppb.Timestamp) string {
t, err := Timestamp(ts)
if err != nil {
return fmt.Sprintf("(%v)", err)
}
return t.Format(time.RFC3339Nano)
}
// validateTimestamp determines whether a Timestamp is valid.
// A valid timestamp represents a time in the range [0001-01-01, 10000-01-01)
// and has a Nanos field in the range [0, 1e9).
//
// If the Timestamp is valid, validateTimestamp returns nil.
// Otherwise, it returns an error that describes the problem.
//
// Every valid Timestamp can be represented by a time.Time,
// but the converse is not true.
func validateTimestamp(ts *timestamppb.Timestamp) error {
if ts == nil {
return errors.New("timestamp: nil Timestamp")
}
if ts.Seconds < minValidSeconds {
return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
}
if ts.Seconds >= maxValidSeconds {
return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
}
if ts.Nanos < 0 || ts.Nanos >= 1e9 {
return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
}
return nil
}

View File

@ -1,64 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: github.com/golang/protobuf/ptypes/timestamp/timestamp.proto
package timestamp
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
)
// Symbols defined in public import of google/protobuf/timestamp.proto.
type Timestamp = timestamppb.Timestamp
var File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto protoreflect.FileDescriptor
var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = []byte{
0x0a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x74, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x37,
0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3b, 0x74, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = []interface{}{}
var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() }
func file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() {
if File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes,
DependencyIndexes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs,
}.Build()
File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto = out.File
file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = nil
file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = nil
file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = nil
}

4
vendor/golang.org/x/crypto/LICENSE generated vendored
View File

@ -1,4 +1,4 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

View File

@ -11,9 +11,7 @@
// operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”.
//
// Beginning with Go 1.13, the functionality of this package was moved to the
// standard library as crypto/ed25519. This package only acts as a compatibility
// wrapper.
// This package is a wrapper around the standard library crypto/ed25519 package.
package ed25519
import (

View File

@ -16,7 +16,7 @@ Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
choose, you can pass the `New` functions from the different SHA packages to
pbkdf2.Key.
*/
package pbkdf2 // import "golang.org/x/crypto/pbkdf2"
package pbkdf2
import (
"crypto/hmac"

4
vendor/golang.org/x/net/LICENSE generated vendored
View File

@ -1,4 +1,4 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

View File

@ -17,6 +17,7 @@ package http2 // import "golang.org/x/net/http2"
import (
"bufio"
"context"
"crypto/tls"
"fmt"
"io"
@ -26,6 +27,7 @@ import (
"strconv"
"strings"
"sync"
"time"
"golang.org/x/net/http/httpguts"
)
@ -210,12 +212,6 @@ type stringWriter interface {
WriteString(s string) (n int, err error)
}
// A gate lets two goroutines coordinate their activities.
type gate chan struct{}
func (g gate) Done() { g <- struct{}{} }
func (g gate) Wait() { <-g }
// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
type closeWaiter chan struct{}
@ -383,3 +379,14 @@ func validPseudoPath(v string) bool {
// makes that struct also non-comparable, and generally doesn't add
// any size (as long as it's first).
type incomparable [0]func()
// synctestGroupInterface is the methods of synctestGroup used by Server and Transport.
// It's defined as an interface here to let us keep synctestGroup entirely test-only
// and not a part of non-test builds.
type synctestGroupInterface interface {
Join()
Now() time.Time
NewTimer(d time.Duration) timer
AfterFunc(d time.Duration, f func()) timer
ContextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc)
}

View File

@ -154,6 +154,39 @@ type Server struct {
// so that we don't embed a Mutex in this struct, which will make the
// struct non-copyable, which might break some callers.
state *serverInternalState
// Synchronization group used for testing.
// Outside of tests, this is nil.
group synctestGroupInterface
}
func (s *Server) markNewGoroutine() {
if s.group != nil {
s.group.Join()
}
}
func (s *Server) now() time.Time {
if s.group != nil {
return s.group.Now()
}
return time.Now()
}
// newTimer creates a new time.Timer, or a synthetic timer in tests.
func (s *Server) newTimer(d time.Duration) timer {
if s.group != nil {
return s.group.NewTimer(d)
}
return timeTimer{time.NewTimer(d)}
}
// afterFunc creates a new time.AfterFunc timer, or a synthetic timer in tests.
func (s *Server) afterFunc(d time.Duration, f func()) timer {
if s.group != nil {
return s.group.AfterFunc(d, f)
}
return timeTimer{time.AfterFunc(d, f)}
}
func (s *Server) initialConnRecvWindowSize() int32 {
@ -400,6 +433,10 @@ func (o *ServeConnOpts) handler() http.Handler {
//
// The opts parameter is optional. If nil, default values are used.
func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
s.serveConn(c, opts, nil)
}
func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverConn)) {
baseCtx, cancel := serverConnBaseContext(c, opts)
defer cancel()
@ -426,6 +463,9 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
pushEnabled: true,
sawClientPreface: opts.SawClientPreface,
}
if newf != nil {
newf(sc)
}
s.state.registerConn(sc)
defer s.state.unregisterConn(sc)
@ -599,8 +639,8 @@ type serverConn struct {
inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop
needToSendGoAway bool // we need to schedule a GOAWAY frame write
goAwayCode ErrCode
shutdownTimer *time.Timer // nil until used
idleTimer *time.Timer // nil if unused
shutdownTimer timer // nil until used
idleTimer timer // nil if unused
// Owned by the writeFrameAsync goroutine:
headerWriteBuf bytes.Buffer
@ -649,12 +689,12 @@ type stream struct {
flow outflow // limits writing from Handler to client
inflow inflow // what the client is allowed to POST/etc to us
state streamState
resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
gotTrailerHeader bool // HEADER frame for trailers was seen
wroteHeaders bool // whether we wrote headers (not status 100)
readDeadline *time.Timer // nil if unused
writeDeadline *time.Timer // nil if unused
closeErr error // set before cw is closed
resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
gotTrailerHeader bool // HEADER frame for trailers was seen
wroteHeaders bool // whether we wrote headers (not status 100)
readDeadline timer // nil if unused
writeDeadline timer // nil if unused
closeErr error // set before cw is closed
trailer http.Header // accumulated trailers
reqTrailer http.Header // handler's Request.Trailer
@ -811,8 +851,9 @@ type readFrameResult struct {
// consumer is done with the frame.
// It's run on its own goroutine.
func (sc *serverConn) readFrames() {
gate := make(gate)
gateDone := gate.Done
sc.srv.markNewGoroutine()
gate := make(chan struct{})
gateDone := func() { gate <- struct{}{} }
for {
f, err := sc.framer.ReadFrame()
select {
@ -843,6 +884,7 @@ type frameWriteResult struct {
// At most one goroutine can be running writeFrameAsync at a time per
// serverConn.
func (sc *serverConn) writeFrameAsync(wr FrameWriteRequest, wd *writeData) {
sc.srv.markNewGoroutine()
var err error
if wd == nil {
err = wr.write.writeFrame(sc)
@ -922,13 +964,13 @@ func (sc *serverConn) serve() {
sc.setConnState(http.StateIdle)
if sc.srv.IdleTimeout > 0 {
sc.idleTimer = time.AfterFunc(sc.srv.IdleTimeout, sc.onIdleTimer)
sc.idleTimer = sc.srv.afterFunc(sc.srv.IdleTimeout, sc.onIdleTimer)
defer sc.idleTimer.Stop()
}
go sc.readFrames() // closed by defer sc.conn.Close above
settingsTimer := time.AfterFunc(firstSettingsTimeout, sc.onSettingsTimer)
settingsTimer := sc.srv.afterFunc(firstSettingsTimeout, sc.onSettingsTimer)
defer settingsTimer.Stop()
loopNum := 0
@ -1057,10 +1099,10 @@ func (sc *serverConn) readPreface() error {
errc <- nil
}
}()
timer := time.NewTimer(prefaceTimeout) // TODO: configurable on *Server?
timer := sc.srv.newTimer(prefaceTimeout) // TODO: configurable on *Server?
defer timer.Stop()
select {
case <-timer.C:
case <-timer.C():
return errPrefaceTimeout
case err := <-errc:
if err == nil {
@ -1425,7 +1467,7 @@ func (sc *serverConn) goAway(code ErrCode) {
func (sc *serverConn) shutDownIn(d time.Duration) {
sc.serveG.check()
sc.shutdownTimer = time.AfterFunc(d, sc.onShutdownTimer)
sc.shutdownTimer = sc.srv.afterFunc(d, sc.onShutdownTimer)
}
func (sc *serverConn) resetStream(se StreamError) {
@ -1639,7 +1681,7 @@ func (sc *serverConn) closeStream(st *stream, err error) {
delete(sc.streams, st.id)
if len(sc.streams) == 0 {
sc.setConnState(http.StateIdle)
if sc.srv.IdleTimeout > 0 {
if sc.srv.IdleTimeout > 0 && sc.idleTimer != nil {
sc.idleTimer.Reset(sc.srv.IdleTimeout)
}
if h1ServerKeepAlivesDisabled(sc.hs) {
@ -1661,6 +1703,7 @@ func (sc *serverConn) closeStream(st *stream, err error) {
}
}
st.closeErr = err
st.cancelCtx()
st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
sc.writeSched.CloseStream(st.id)
}
@ -2021,7 +2064,7 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
// (in Go 1.8), though. That's a more sane option anyway.
if sc.hs.ReadTimeout > 0 {
sc.conn.SetReadDeadline(time.Time{})
st.readDeadline = time.AfterFunc(sc.hs.ReadTimeout, st.onReadTimeout)
st.readDeadline = sc.srv.afterFunc(sc.hs.ReadTimeout, st.onReadTimeout)
}
return sc.scheduleHandler(id, rw, req, handler)
@ -2119,7 +2162,7 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream
st.flow.add(sc.initialStreamSendWindowSize)
st.inflow.init(sc.srv.initialStreamRecvWindowSize())
if sc.hs.WriteTimeout > 0 {
st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout)
st.writeDeadline = sc.srv.afterFunc(sc.hs.WriteTimeout, st.onWriteTimeout)
}
sc.streams[id] = st
@ -2343,6 +2386,7 @@ func (sc *serverConn) handlerDone() {
// Run on its own goroutine.
func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) {
sc.srv.markNewGoroutine()
defer sc.sendServeMsg(handlerDoneMsg)
didPanic := true
defer func() {
@ -2639,7 +2683,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
var date string
if _, ok := rws.snapHeader["Date"]; !ok {
// TODO(bradfitz): be faster here, like net/http? measure.
date = time.Now().UTC().Format(http.TimeFormat)
date = rws.conn.srv.now().UTC().Format(http.TimeFormat)
}
for _, v := range rws.snapHeader["Trailer"] {
@ -2761,7 +2805,7 @@ func (rws *responseWriterState) promoteUndeclaredTrailers() {
func (w *responseWriter) SetReadDeadline(deadline time.Time) error {
st := w.rws.stream
if !deadline.IsZero() && deadline.Before(time.Now()) {
if !deadline.IsZero() && deadline.Before(w.rws.conn.srv.now()) {
// If we're setting a deadline in the past, reset the stream immediately
// so writes after SetWriteDeadline returns will fail.
st.onReadTimeout()
@ -2777,9 +2821,9 @@ func (w *responseWriter) SetReadDeadline(deadline time.Time) error {
if deadline.IsZero() {
st.readDeadline = nil
} else if st.readDeadline == nil {
st.readDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onReadTimeout)
st.readDeadline = sc.srv.afterFunc(deadline.Sub(sc.srv.now()), st.onReadTimeout)
} else {
st.readDeadline.Reset(deadline.Sub(time.Now()))
st.readDeadline.Reset(deadline.Sub(sc.srv.now()))
}
})
return nil
@ -2787,7 +2831,7 @@ func (w *responseWriter) SetReadDeadline(deadline time.Time) error {
func (w *responseWriter) SetWriteDeadline(deadline time.Time) error {
st := w.rws.stream
if !deadline.IsZero() && deadline.Before(time.Now()) {
if !deadline.IsZero() && deadline.Before(w.rws.conn.srv.now()) {
// If we're setting a deadline in the past, reset the stream immediately
// so writes after SetWriteDeadline returns will fail.
st.onWriteTimeout()
@ -2803,9 +2847,9 @@ func (w *responseWriter) SetWriteDeadline(deadline time.Time) error {
if deadline.IsZero() {
st.writeDeadline = nil
} else if st.writeDeadline == nil {
st.writeDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onWriteTimeout)
st.writeDeadline = sc.srv.afterFunc(deadline.Sub(sc.srv.now()), st.onWriteTimeout)
} else {
st.writeDeadline.Reset(deadline.Sub(time.Now()))
st.writeDeadline.Reset(deadline.Sub(sc.srv.now()))
}
})
return nil

View File

@ -1,331 +0,0 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package http2
import (
"context"
"sync"
"time"
)
// testSyncHooks coordinates goroutines in tests.
//
// For example, a call to ClientConn.RoundTrip involves several goroutines, including:
// - the goroutine running RoundTrip;
// - the clientStream.doRequest goroutine, which writes the request; and
// - the clientStream.readLoop goroutine, which reads the response.
//
// Using testSyncHooks, a test can start a RoundTrip and identify when all these goroutines
// are blocked waiting for some condition such as reading the Request.Body or waiting for
// flow control to become available.
//
// The testSyncHooks also manage timers and synthetic time in tests.
// This permits us to, for example, start a request and cause it to time out waiting for
// response headers without resorting to time.Sleep calls.
type testSyncHooks struct {
// active/inactive act as a mutex and condition variable.
//
// - neither chan contains a value: testSyncHooks is locked.
// - active contains a value: unlocked, and at least one goroutine is not blocked
// - inactive contains a value: unlocked, and all goroutines are blocked
active chan struct{}
inactive chan struct{}
// goroutine counts
total int // total goroutines
condwait map[*sync.Cond]int // blocked in sync.Cond.Wait
blocked []*testBlockedGoroutine // otherwise blocked
// fake time
now time.Time
timers []*fakeTimer
// Transport testing: Report various events.
newclientconn func(*ClientConn)
newstream func(*clientStream)
}
// testBlockedGoroutine is a blocked goroutine.
type testBlockedGoroutine struct {
f func() bool // blocked until f returns true
ch chan struct{} // closed when unblocked
}
func newTestSyncHooks() *testSyncHooks {
h := &testSyncHooks{
active: make(chan struct{}, 1),
inactive: make(chan struct{}, 1),
condwait: map[*sync.Cond]int{},
}
h.inactive <- struct{}{}
h.now = time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
return h
}
// lock acquires the testSyncHooks mutex.
func (h *testSyncHooks) lock() {
select {
case <-h.active:
case <-h.inactive:
}
}
// waitInactive waits for all goroutines to become inactive.
func (h *testSyncHooks) waitInactive() {
for {
<-h.inactive
if !h.unlock() {
break
}
}
}
// unlock releases the testSyncHooks mutex.
// It reports whether any goroutines are active.
func (h *testSyncHooks) unlock() (active bool) {
// Look for a blocked goroutine which can be unblocked.
blocked := h.blocked[:0]
unblocked := false
for _, b := range h.blocked {
if !unblocked && b.f() {
unblocked = true
close(b.ch)
} else {
blocked = append(blocked, b)
}
}
h.blocked = blocked
// Count goroutines blocked on condition variables.
condwait := 0
for _, count := range h.condwait {
condwait += count
}
if h.total > condwait+len(blocked) {
h.active <- struct{}{}
return true
} else {
h.inactive <- struct{}{}
return false
}
}
// goRun starts a new goroutine.
func (h *testSyncHooks) goRun(f func()) {
h.lock()
h.total++
h.unlock()
go func() {
defer func() {
h.lock()
h.total--
h.unlock()
}()
f()
}()
}
// blockUntil indicates that a goroutine is blocked waiting for some condition to become true.
// It waits until f returns true before proceeding.
//
// Example usage:
//
// h.blockUntil(func() bool {
// // Is the context done yet?
// select {
// case <-ctx.Done():
// default:
// return false
// }
// return true
// })
// // Wait for the context to become done.
// <-ctx.Done()
//
// The function f passed to blockUntil must be non-blocking and idempotent.
func (h *testSyncHooks) blockUntil(f func() bool) {
if f() {
return
}
ch := make(chan struct{})
h.lock()
h.blocked = append(h.blocked, &testBlockedGoroutine{
f: f,
ch: ch,
})
h.unlock()
<-ch
}
// broadcast is sync.Cond.Broadcast.
func (h *testSyncHooks) condBroadcast(cond *sync.Cond) {
h.lock()
delete(h.condwait, cond)
h.unlock()
cond.Broadcast()
}
// broadcast is sync.Cond.Wait.
func (h *testSyncHooks) condWait(cond *sync.Cond) {
h.lock()
h.condwait[cond]++
h.unlock()
}
// newTimer creates a new fake timer.
func (h *testSyncHooks) newTimer(d time.Duration) timer {
h.lock()
defer h.unlock()
t := &fakeTimer{
hooks: h,
when: h.now.Add(d),
c: make(chan time.Time),
}
h.timers = append(h.timers, t)
return t
}
// afterFunc creates a new fake AfterFunc timer.
func (h *testSyncHooks) afterFunc(d time.Duration, f func()) timer {
h.lock()
defer h.unlock()
t := &fakeTimer{
hooks: h,
when: h.now.Add(d),
f: f,
}
h.timers = append(h.timers, t)
return t
}
func (h *testSyncHooks) contextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) {
ctx, cancel := context.WithCancel(ctx)
t := h.afterFunc(d, cancel)
return ctx, func() {
t.Stop()
cancel()
}
}
func (h *testSyncHooks) timeUntilEvent() time.Duration {
h.lock()
defer h.unlock()
var next time.Time
for _, t := range h.timers {
if next.IsZero() || t.when.Before(next) {
next = t.when
}
}
if d := next.Sub(h.now); d > 0 {
return d
}
return 0
}
// advance advances time and causes synthetic timers to fire.
func (h *testSyncHooks) advance(d time.Duration) {
h.lock()
defer h.unlock()
h.now = h.now.Add(d)
timers := h.timers[:0]
for _, t := range h.timers {
t := t // remove after go.mod depends on go1.22
t.mu.Lock()
switch {
case t.when.After(h.now):
timers = append(timers, t)
case t.when.IsZero():
// stopped timer
default:
t.when = time.Time{}
if t.c != nil {
close(t.c)
}
if t.f != nil {
h.total++
go func() {
defer func() {
h.lock()
h.total--
h.unlock()
}()
t.f()
}()
}
}
t.mu.Unlock()
}
h.timers = timers
}
// A timer wraps a time.Timer, or a synthetic equivalent in tests.
// Unlike time.Timer, timer is single-use: The timer channel is closed when the timer expires.
type timer interface {
C() <-chan time.Time
Stop() bool
Reset(d time.Duration) bool
}
// timeTimer implements timer using real time.
type timeTimer struct {
t *time.Timer
c chan time.Time
}
// newTimeTimer creates a new timer using real time.
func newTimeTimer(d time.Duration) timer {
ch := make(chan time.Time)
t := time.AfterFunc(d, func() {
close(ch)
})
return &timeTimer{t, ch}
}
// newTimeAfterFunc creates an AfterFunc timer using real time.
func newTimeAfterFunc(d time.Duration, f func()) timer {
return &timeTimer{
t: time.AfterFunc(d, f),
}
}
func (t timeTimer) C() <-chan time.Time { return t.c }
func (t timeTimer) Stop() bool { return t.t.Stop() }
func (t timeTimer) Reset(d time.Duration) bool { return t.t.Reset(d) }
// fakeTimer implements timer using fake time.
type fakeTimer struct {
hooks *testSyncHooks
mu sync.Mutex
when time.Time // when the timer will fire
c chan time.Time // closed when the timer fires; mutually exclusive with f
f func() // called when the timer fires; mutually exclusive with c
}
func (t *fakeTimer) C() <-chan time.Time { return t.c }
func (t *fakeTimer) Stop() bool {
t.mu.Lock()
defer t.mu.Unlock()
stopped := t.when.IsZero()
t.when = time.Time{}
return stopped
}
func (t *fakeTimer) Reset(d time.Duration) bool {
if t.c != nil || t.f == nil {
panic("fakeTimer only supports Reset on AfterFunc timers")
}
t.mu.Lock()
defer t.mu.Unlock()
t.hooks.lock()
defer t.hooks.unlock()
active := !t.when.IsZero()
t.when = t.hooks.now.Add(d)
if !active {
t.hooks.timers = append(t.hooks.timers, t)
}
return active
}

20
vendor/golang.org/x/net/http2/timer.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package http2
import "time"
// A timer is a time.Timer, as an interface which can be replaced in tests.
type timer = interface {
C() <-chan time.Time
Reset(d time.Duration) bool
Stop() bool
}
// timeTimer adapts a time.Timer to the timer interface.
type timeTimer struct {
*time.Timer
}
func (t timeTimer) C() <-chan time.Time { return t.Timer.C }

View File

@ -185,7 +185,45 @@ type Transport struct {
connPoolOnce sync.Once
connPoolOrDef ClientConnPool // non-nil version of ConnPool
syncHooks *testSyncHooks
*transportTestHooks
}
// Hook points used for testing.
// Outside of tests, t.transportTestHooks is nil and these all have minimal implementations.
// Inside tests, see the testSyncHooks function docs.
type transportTestHooks struct {
newclientconn func(*ClientConn)
group synctestGroupInterface
}
func (t *Transport) markNewGoroutine() {
if t != nil && t.transportTestHooks != nil {
t.transportTestHooks.group.Join()
}
}
// newTimer creates a new time.Timer, or a synthetic timer in tests.
func (t *Transport) newTimer(d time.Duration) timer {
if t.transportTestHooks != nil {
return t.transportTestHooks.group.NewTimer(d)
}
return timeTimer{time.NewTimer(d)}
}
// afterFunc creates a new time.AfterFunc timer, or a synthetic timer in tests.
func (t *Transport) afterFunc(d time.Duration, f func()) timer {
if t.transportTestHooks != nil {
return t.transportTestHooks.group.AfterFunc(d, f)
}
return timeTimer{time.AfterFunc(d, f)}
}
func (t *Transport) contextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) {
if t.transportTestHooks != nil {
return t.transportTestHooks.group.ContextWithTimeout(ctx, d)
}
return context.WithTimeout(ctx, d)
}
func (t *Transport) maxHeaderListSize() uint32 {
@ -352,60 +390,6 @@ type ClientConn struct {
werr error // first write error that has occurred
hbuf bytes.Buffer // HPACK encoder writes into this
henc *hpack.Encoder
syncHooks *testSyncHooks // can be nil
}
// Hook points used for testing.
// Outside of tests, cc.syncHooks is nil and these all have minimal implementations.
// Inside tests, see the testSyncHooks function docs.
// goRun starts a new goroutine.
func (cc *ClientConn) goRun(f func()) {
if cc.syncHooks != nil {
cc.syncHooks.goRun(f)
return
}
go f()
}
// condBroadcast is cc.cond.Broadcast.
func (cc *ClientConn) condBroadcast() {
if cc.syncHooks != nil {
cc.syncHooks.condBroadcast(cc.cond)
}
cc.cond.Broadcast()
}
// condWait is cc.cond.Wait.
func (cc *ClientConn) condWait() {
if cc.syncHooks != nil {
cc.syncHooks.condWait(cc.cond)
}
cc.cond.Wait()
}
// newTimer creates a new time.Timer, or a synthetic timer in tests.
func (cc *ClientConn) newTimer(d time.Duration) timer {
if cc.syncHooks != nil {
return cc.syncHooks.newTimer(d)
}
return newTimeTimer(d)
}
// afterFunc creates a new time.AfterFunc timer, or a synthetic timer in tests.
func (cc *ClientConn) afterFunc(d time.Duration, f func()) timer {
if cc.syncHooks != nil {
return cc.syncHooks.afterFunc(d, f)
}
return newTimeAfterFunc(d, f)
}
func (cc *ClientConn) contextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) {
if cc.syncHooks != nil {
return cc.syncHooks.contextWithTimeout(ctx, d)
}
return context.WithTimeout(ctx, d)
}
// clientStream is the state for a single HTTP/2 stream. One of these
@ -487,7 +471,7 @@ func (cs *clientStream) abortStreamLocked(err error) {
// TODO(dneil): Clean up tests where cs.cc.cond is nil.
if cs.cc.cond != nil {
// Wake up writeRequestBody if it is waiting on flow control.
cs.cc.condBroadcast()
cs.cc.cond.Broadcast()
}
}
@ -497,7 +481,7 @@ func (cs *clientStream) abortRequestBodyWrite() {
defer cc.mu.Unlock()
if cs.reqBody != nil && cs.reqBodyClosed == nil {
cs.closeReqBodyLocked()
cc.condBroadcast()
cc.cond.Broadcast()
}
}
@ -507,10 +491,11 @@ func (cs *clientStream) closeReqBodyLocked() {
}
cs.reqBodyClosed = make(chan struct{})
reqBodyClosed := cs.reqBodyClosed
cs.cc.goRun(func() {
go func() {
cs.cc.t.markNewGoroutine()
cs.reqBody.Close()
close(reqBodyClosed)
})
}()
}
type stickyErrWriter struct {
@ -626,21 +611,7 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
backoff := float64(uint(1) << (uint(retry) - 1))
backoff += backoff * (0.1 * mathrand.Float64())
d := time.Second * time.Duration(backoff)
var tm timer
if t.syncHooks != nil {
tm = t.syncHooks.newTimer(d)
t.syncHooks.blockUntil(func() bool {
select {
case <-tm.C():
case <-req.Context().Done():
default:
return false
}
return true
})
} else {
tm = newTimeTimer(d)
}
tm := t.newTimer(d)
select {
case <-tm.C():
t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)
@ -725,8 +696,8 @@ func canRetryError(err error) bool {
}
func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) {
if t.syncHooks != nil {
return t.newClientConn(nil, singleUse, t.syncHooks)
if t.transportTestHooks != nil {
return t.newClientConn(nil, singleUse)
}
host, _, err := net.SplitHostPort(addr)
if err != nil {
@ -736,7 +707,7 @@ func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse b
if err != nil {
return nil, err
}
return t.newClientConn(tconn, singleUse, nil)
return t.newClientConn(tconn, singleUse)
}
func (t *Transport) newTLSConfig(host string) *tls.Config {
@ -802,10 +773,10 @@ func (t *Transport) maxEncoderHeaderTableSize() uint32 {
}
func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
return t.newClientConn(c, t.disableKeepAlives(), nil)
return t.newClientConn(c, t.disableKeepAlives())
}
func (t *Transport) newClientConn(c net.Conn, singleUse bool, hooks *testSyncHooks) (*ClientConn, error) {
func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) {
cc := &ClientConn{
t: t,
tconn: c,
@ -820,16 +791,12 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool, hooks *testSyncHoo
wantSettingsAck: true,
pings: make(map[[8]byte]chan struct{}),
reqHeaderMu: make(chan struct{}, 1),
syncHooks: hooks,
}
if hooks != nil {
hooks.newclientconn(cc)
if t.transportTestHooks != nil {
t.markNewGoroutine()
t.transportTestHooks.newclientconn(cc)
c = cc.tconn
}
if d := t.idleConnTimeout(); d != 0 {
cc.idleTimeout = d
cc.idleTimer = cc.afterFunc(d, cc.onIdleTimeout)
}
if VerboseLogs {
t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr())
}
@ -860,10 +827,6 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool, hooks *testSyncHoo
cc.henc.SetMaxDynamicTableSizeLimit(t.maxEncoderHeaderTableSize())
cc.peerMaxHeaderTableSize = initialHeaderTableSize
if t.AllowHTTP {
cc.nextStreamID = 3
}
if cs, ok := c.(connectionStater); ok {
state := cs.ConnectionState()
cc.tlsState = &state
@ -893,7 +856,13 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool, hooks *testSyncHoo
return nil, cc.werr
}
cc.goRun(cc.readLoop)
// Start the idle timer after the connection is fully initialized.
if d := t.idleConnTimeout(); d != 0 {
cc.idleTimeout = d
cc.idleTimer = t.afterFunc(d, cc.onIdleTimeout)
}
go cc.readLoop()
return cc, nil
}
@ -901,7 +870,7 @@ func (cc *ClientConn) healthCheck() {
pingTimeout := cc.t.pingTimeout()
// We don't need to periodically ping in the health check, because the readLoop of ClientConn will
// trigger the healthCheck again if there is no frame received.
ctx, cancel := cc.contextWithTimeout(context.Background(), pingTimeout)
ctx, cancel := cc.t.contextWithTimeout(context.Background(), pingTimeout)
defer cancel()
cc.vlogf("http2: Transport sending health check")
err := cc.Ping(ctx)
@ -1144,7 +1113,8 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error {
// Wait for all in-flight streams to complete or connection to close
done := make(chan struct{})
cancelled := false // guarded by cc.mu
cc.goRun(func() {
go func() {
cc.t.markNewGoroutine()
cc.mu.Lock()
defer cc.mu.Unlock()
for {
@ -1156,9 +1126,9 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error {
if cancelled {
break
}
cc.condWait()
cc.cond.Wait()
}
})
}()
shutdownEnterWaitStateHook()
select {
case <-done:
@ -1168,7 +1138,7 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error {
cc.mu.Lock()
// Free the goroutine above
cancelled = true
cc.condBroadcast()
cc.cond.Broadcast()
cc.mu.Unlock()
return ctx.Err()
}
@ -1206,7 +1176,7 @@ func (cc *ClientConn) closeForError(err error) {
for _, cs := range cc.streams {
cs.abortStreamLocked(err)
}
cc.condBroadcast()
cc.cond.Broadcast()
cc.mu.Unlock()
cc.closeConn()
}
@ -1321,23 +1291,30 @@ func (cc *ClientConn) roundTrip(req *http.Request, streamf func(*clientStream))
respHeaderRecv: make(chan struct{}),
donec: make(chan struct{}),
}
cc.goRun(func() {
cs.doRequest(req)
})
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
if !cc.t.disableCompression() &&
req.Header.Get("Accept-Encoding") == "" &&
req.Header.Get("Range") == "" &&
!cs.isHead {
// Request gzip only, not deflate. Deflate is ambiguous and
// not as universally supported anyway.
// See: https://zlib.net/zlib_faq.html#faq39
//
// Note that we don't request this for HEAD requests,
// due to a bug in nginx:
// http://trac.nginx.org/nginx/ticket/358
// https://golang.org/issue/5522
//
// We don't request gzip if the request is for a range, since
// auto-decoding a portion of a gzipped document will just fail
// anyway. See https://golang.org/issue/8923
cs.requestedGzip = true
}
go cs.doRequest(req, streamf)
waitDone := func() error {
if cc.syncHooks != nil {
cc.syncHooks.blockUntil(func() bool {
select {
case <-cs.donec:
case <-ctx.Done():
case <-cs.reqCancel:
default:
return false
}
return true
})
}
select {
case <-cs.donec:
return nil
@ -1398,24 +1375,7 @@ func (cc *ClientConn) roundTrip(req *http.Request, streamf func(*clientStream))
return err
}
if streamf != nil {
streamf(cs)
}
for {
if cc.syncHooks != nil {
cc.syncHooks.blockUntil(func() bool {
select {
case <-cs.respHeaderRecv:
case <-cs.abort:
case <-ctx.Done():
case <-cs.reqCancel:
default:
return false
}
return true
})
}
select {
case <-cs.respHeaderRecv:
return handleResponseHeaders()
@ -1445,8 +1405,9 @@ func (cc *ClientConn) roundTrip(req *http.Request, streamf func(*clientStream))
// doRequest runs for the duration of the request lifetime.
//
// It sends the request and performs post-request cleanup (closing Request.Body, etc.).
func (cs *clientStream) doRequest(req *http.Request) {
err := cs.writeRequest(req)
func (cs *clientStream) doRequest(req *http.Request, streamf func(*clientStream)) {
cs.cc.t.markNewGoroutine()
err := cs.writeRequest(req, streamf)
cs.cleanupWriteRequest(err)
}
@ -1457,7 +1418,7 @@ func (cs *clientStream) doRequest(req *http.Request) {
//
// It returns non-nil if the request ends otherwise.
// If the returned error is StreamError, the error Code may be used in resetting the stream.
func (cs *clientStream) writeRequest(req *http.Request) (err error) {
func (cs *clientStream) writeRequest(req *http.Request, streamf func(*clientStream)) (err error) {
cc := cs.cc
ctx := cs.ctx
@ -1471,21 +1432,6 @@ func (cs *clientStream) writeRequest(req *http.Request) (err error) {
if cc.reqHeaderMu == nil {
panic("RoundTrip on uninitialized ClientConn") // for tests
}
var newStreamHook func(*clientStream)
if cc.syncHooks != nil {
newStreamHook = cc.syncHooks.newstream
cc.syncHooks.blockUntil(func() bool {
select {
case cc.reqHeaderMu <- struct{}{}:
<-cc.reqHeaderMu
case <-cs.reqCancel:
case <-ctx.Done():
default:
return false
}
return true
})
}
select {
case cc.reqHeaderMu <- struct{}{}:
case <-cs.reqCancel:
@ -1510,28 +1456,8 @@ func (cs *clientStream) writeRequest(req *http.Request) (err error) {
}
cc.mu.Unlock()
if newStreamHook != nil {
newStreamHook(cs)
}
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
if !cc.t.disableCompression() &&
req.Header.Get("Accept-Encoding") == "" &&
req.Header.Get("Range") == "" &&
!cs.isHead {
// Request gzip only, not deflate. Deflate is ambiguous and
// not as universally supported anyway.
// See: https://zlib.net/zlib_faq.html#faq39
//
// Note that we don't request this for HEAD requests,
// due to a bug in nginx:
// http://trac.nginx.org/nginx/ticket/358
// https://golang.org/issue/5522
//
// We don't request gzip if the request is for a range, since
// auto-decoding a portion of a gzipped document will just fail
// anyway. See https://golang.org/issue/8923
cs.requestedGzip = true
if streamf != nil {
streamf(cs)
}
continueTimeout := cc.t.expectContinueTimeout()
@ -1594,7 +1520,7 @@ func (cs *clientStream) writeRequest(req *http.Request) (err error) {
var respHeaderTimer <-chan time.Time
var respHeaderRecv chan struct{}
if d := cc.responseHeaderTimeout(); d != 0 {
timer := cc.newTimer(d)
timer := cc.t.newTimer(d)
defer timer.Stop()
respHeaderTimer = timer.C()
respHeaderRecv = cs.respHeaderRecv
@ -1603,21 +1529,6 @@ func (cs *clientStream) writeRequest(req *http.Request) (err error) {
// or until the request is aborted (via context, error, or otherwise),
// whichever comes first.
for {
if cc.syncHooks != nil {
cc.syncHooks.blockUntil(func() bool {
select {
case <-cs.peerClosed:
case <-respHeaderTimer:
case <-respHeaderRecv:
case <-cs.abort:
case <-ctx.Done():
case <-cs.reqCancel:
default:
return false
}
return true
})
}
select {
case <-cs.peerClosed:
return nil
@ -1766,7 +1677,7 @@ func (cc *ClientConn) awaitOpenSlotForStreamLocked(cs *clientStream) error {
return nil
}
cc.pendingRequests++
cc.condWait()
cc.cond.Wait()
cc.pendingRequests--
select {
case <-cs.abort:
@ -2028,7 +1939,7 @@ func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error)
cs.flow.take(take)
return take, nil
}
cc.condWait()
cc.cond.Wait()
}
}
@ -2311,7 +2222,7 @@ func (cc *ClientConn) forgetStreamID(id uint32) {
}
// Wake up writeRequestBody via clientStream.awaitFlowControl and
// wake up RoundTrip if there is a pending request.
cc.condBroadcast()
cc.cond.Broadcast()
closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives() || cc.goAway != nil
if closeOnIdle && cc.streamsReserved == 0 && len(cc.streams) == 0 {
@ -2333,6 +2244,7 @@ type clientConnReadLoop struct {
// readLoop runs in its own goroutine and reads and dispatches frames.
func (cc *ClientConn) readLoop() {
cc.t.markNewGoroutine()
rl := &clientConnReadLoop{cc: cc}
defer rl.cleanup()
cc.readerErr = rl.run()
@ -2399,7 +2311,7 @@ func (rl *clientConnReadLoop) cleanup() {
cs.abortStreamLocked(err)
}
}
cc.condBroadcast()
cc.cond.Broadcast()
cc.mu.Unlock()
}
@ -2436,7 +2348,7 @@ func (rl *clientConnReadLoop) run() error {
readIdleTimeout := cc.t.ReadIdleTimeout
var t timer
if readIdleTimeout != 0 {
t = cc.afterFunc(readIdleTimeout, cc.healthCheck)
t = cc.t.afterFunc(readIdleTimeout, cc.healthCheck)
}
for {
f, err := cc.fr.ReadFrame()
@ -3034,7 +2946,7 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
for _, cs := range cc.streams {
cs.flow.add(delta)
}
cc.condBroadcast()
cc.cond.Broadcast()
cc.initialWindowSize = s.Val
case SettingHeaderTableSize:
@ -3089,7 +3001,7 @@ func (rl *clientConnReadLoop) processWindowUpdate(f *WindowUpdateFrame) error {
return ConnectionError(ErrCodeFlowControl)
}
cc.condBroadcast()
cc.cond.Broadcast()
return nil
}
@ -3133,7 +3045,8 @@ func (cc *ClientConn) Ping(ctx context.Context) error {
}
var pingError error
errc := make(chan struct{})
cc.goRun(func() {
go func() {
cc.t.markNewGoroutine()
cc.wmu.Lock()
defer cc.wmu.Unlock()
if pingError = cc.fr.WritePing(false, p); pingError != nil {
@ -3144,20 +3057,7 @@ func (cc *ClientConn) Ping(ctx context.Context) error {
close(errc)
return
}
})
if cc.syncHooks != nil {
cc.syncHooks.blockUntil(func() bool {
select {
case <-c:
case <-errc:
case <-ctx.Done():
case <-cc.readerDone:
default:
return false
}
return true
})
}
}()
select {
case <-c:
return nil

View File

@ -443,8 +443,8 @@ func (ws *priorityWriteScheduler) addClosedOrIdleNode(list *[]*priorityNode, max
}
func (ws *priorityWriteScheduler) removeNode(n *priorityNode) {
for k := n.kids; k != nil; k = k.next {
k.setParent(n.parent)
for n.kids != nil {
n.kids.setParent(n.parent)
}
n.setParent(nil)
delete(ws.nodes, n.id)

4
vendor/golang.org/x/sync/LICENSE generated vendored
View File

@ -1,4 +1,4 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

4
vendor/golang.org/x/sys/LICENSE generated vendored
View File

@ -1,4 +1,4 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

View File

@ -58,6 +58,7 @@ includes_Darwin='
#define _DARWIN_USE_64_BIT_INODE
#define __APPLE_USE_RFC_3542
#include <stdint.h>
#include <sys/stdio.h>
#include <sys/attr.h>
#include <sys/clonefile.h>
#include <sys/kern_control.h>

View File

@ -402,6 +402,18 @@ func IoctlSetIfreqMTU(fd int, ifreq *IfreqMTU) error {
return ioctlPtr(fd, SIOCSIFMTU, unsafe.Pointer(ifreq))
}
//sys renamexNp(from string, to string, flag uint32) (err error)
func RenamexNp(from string, to string, flag uint32) (err error) {
return renamexNp(from, to, flag)
}
//sys renameatxNp(fromfd int, from string, tofd int, to string, flag uint32) (err error)
func RenameatxNp(fromfd int, from string, tofd int, to string, flag uint32) (err error) {
return renameatxNp(fromfd, from, tofd, to, flag)
}
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS_SYSCTL
func Uname(uname *Utsname) error {

View File

@ -2592,3 +2592,4 @@ func SchedGetAttr(pid int, flags uint) (*SchedAttr, error) {
}
//sys Cachestat(fd uint, crange *CachestatRange, cstat *Cachestat_t, flags uint) (err error)
//sys Mseal(b []byte, flags uint) (err error)

View File

@ -293,6 +293,7 @@ func Uname(uname *Utsname) error {
//sys Mkfifoat(dirfd int, path string, mode uint32) (err error)
//sys Mknod(path string, mode uint32, dev int) (err error)
//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
//sys Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error)
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error)
//sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error)

View File

@ -1169,6 +1169,11 @@ const (
PT_WRITE_D = 0x5
PT_WRITE_I = 0x4
PT_WRITE_U = 0x6
RENAME_EXCL = 0x4
RENAME_NOFOLLOW_ANY = 0x10
RENAME_RESERVED1 = 0x8
RENAME_SECLUDE = 0x1
RENAME_SWAP = 0x2
RLIMIT_AS = 0x5
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0

View File

@ -1169,6 +1169,11 @@ const (
PT_WRITE_D = 0x5
PT_WRITE_I = 0x4
PT_WRITE_U = 0x6
RENAME_EXCL = 0x4
RENAME_NOFOLLOW_ANY = 0x10
RENAME_RESERVED1 = 0x8
RENAME_SECLUDE = 0x1
RENAME_SWAP = 0x2
RLIMIT_AS = 0x5
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0

View File

@ -457,6 +457,7 @@ const (
B600 = 0x8
B75 = 0x2
B9600 = 0xd
BCACHEFS_SUPER_MAGIC = 0xca451a4e
BDEVFS_MAGIC = 0x62646576
BINDERFS_SUPER_MAGIC = 0x6c6f6f70
BINFMTFS_MAGIC = 0x42494e4d
@ -928,6 +929,7 @@ const (
EPOLL_CTL_ADD = 0x1
EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3
EPOLL_IOC_TYPE = 0x8a
EROFS_SUPER_MAGIC_V1 = 0xe0f5e1e2
ESP_V4_FLOW = 0xa
ESP_V6_FLOW = 0xc
@ -941,9 +943,6 @@ const (
ETHTOOL_FEC_OFF = 0x4
ETHTOOL_FEC_RS = 0x8
ETHTOOL_FLAG_ALL = 0x7
ETHTOOL_FLAG_COMPACT_BITSETS = 0x1
ETHTOOL_FLAG_OMIT_REPLY = 0x2
ETHTOOL_FLAG_STATS = 0x4
ETHTOOL_FLASHDEV = 0x33
ETHTOOL_FLASH_MAX_FILENAME = 0x80
ETHTOOL_FWVERS_LEN = 0x20
@ -1705,6 +1704,7 @@ const (
KEXEC_ARCH_S390 = 0x160000
KEXEC_ARCH_SH = 0x2a0000
KEXEC_ARCH_X86_64 = 0x3e0000
KEXEC_CRASH_HOTPLUG_SUPPORT = 0x8
KEXEC_FILE_DEBUG = 0x8
KEXEC_FILE_NO_INITRAMFS = 0x4
KEXEC_FILE_ON_CRASH = 0x2
@ -1780,6 +1780,7 @@ const (
KEY_SPEC_USER_KEYRING = -0x4
KEY_SPEC_USER_SESSION_KEYRING = -0x5
LANDLOCK_ACCESS_FS_EXECUTE = 0x1
LANDLOCK_ACCESS_FS_IOCTL_DEV = 0x8000
LANDLOCK_ACCESS_FS_MAKE_BLOCK = 0x800
LANDLOCK_ACCESS_FS_MAKE_CHAR = 0x40
LANDLOCK_ACCESS_FS_MAKE_DIR = 0x80
@ -1861,6 +1862,19 @@ const (
MAP_FILE = 0x0
MAP_FIXED = 0x10
MAP_FIXED_NOREPLACE = 0x100000
MAP_HUGE_16GB = 0x88000000
MAP_HUGE_16KB = 0x38000000
MAP_HUGE_16MB = 0x60000000
MAP_HUGE_1GB = 0x78000000
MAP_HUGE_1MB = 0x50000000
MAP_HUGE_256MB = 0x70000000
MAP_HUGE_2GB = 0x7c000000
MAP_HUGE_2MB = 0x54000000
MAP_HUGE_32MB = 0x64000000
MAP_HUGE_512KB = 0x4c000000
MAP_HUGE_512MB = 0x74000000
MAP_HUGE_64KB = 0x40000000
MAP_HUGE_8MB = 0x5c000000
MAP_HUGE_MASK = 0x3f
MAP_HUGE_SHIFT = 0x1a
MAP_PRIVATE = 0x2
@ -2498,6 +2512,23 @@ const (
PR_PAC_GET_ENABLED_KEYS = 0x3d
PR_PAC_RESET_KEYS = 0x36
PR_PAC_SET_ENABLED_KEYS = 0x3c
PR_PPC_DEXCR_CTRL_CLEAR = 0x4
PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC = 0x10
PR_PPC_DEXCR_CTRL_EDITABLE = 0x1
PR_PPC_DEXCR_CTRL_MASK = 0x1f
PR_PPC_DEXCR_CTRL_SET = 0x2
PR_PPC_DEXCR_CTRL_SET_ONEXEC = 0x8
PR_PPC_DEXCR_IBRTPD = 0x1
PR_PPC_DEXCR_NPHIE = 0x3
PR_PPC_DEXCR_SBHE = 0x0
PR_PPC_DEXCR_SRAPD = 0x2
PR_PPC_GET_DEXCR = 0x48
PR_PPC_SET_DEXCR = 0x49
PR_RISCV_CTX_SW_FENCEI_OFF = 0x1
PR_RISCV_CTX_SW_FENCEI_ON = 0x0
PR_RISCV_SCOPE_PER_PROCESS = 0x0
PR_RISCV_SCOPE_PER_THREAD = 0x1
PR_RISCV_SET_ICACHE_FLUSH_CTX = 0x47
PR_RISCV_V_GET_CONTROL = 0x46
PR_RISCV_V_SET_CONTROL = 0x45
PR_RISCV_V_VSTATE_CTRL_CUR_MASK = 0x3
@ -3192,6 +3223,7 @@ const (
STATX_MTIME = 0x40
STATX_NLINK = 0x4
STATX_SIZE = 0x200
STATX_SUBVOL = 0x8000
STATX_TYPE = 0x1
STATX_UID = 0x8
STATX__RESERVED = 0x80000000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x800
EPIOCGPARAMS = 0x80088a02
EPIOCSPARAMS = 0x40088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x800
EPIOCGPARAMS = 0x80088a02
EPIOCSPARAMS = 0x40088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x800
EPIOCGPARAMS = 0x80088a02
EPIOCSPARAMS = 0x40088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x800
EPIOCGPARAMS = 0x80088a02
EPIOCSPARAMS = 0x40088a01
EPOLL_CLOEXEC = 0x80000
ESR_MAGIC = 0x45535201
EXTPROC = 0x10000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x800
EPIOCGPARAMS = 0x80088a02
EPIOCSPARAMS = 0x40088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x80
EPIOCGPARAMS = 0x40088a02
EPIOCSPARAMS = 0x80088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x80
EPIOCGPARAMS = 0x40088a02
EPIOCSPARAMS = 0x80088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x80
EPIOCGPARAMS = 0x40088a02
EPIOCSPARAMS = 0x80088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x80
EPIOCGPARAMS = 0x40088a02
EPIOCSPARAMS = 0x80088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x20
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x800
EPIOCGPARAMS = 0x40088a02
EPIOCSPARAMS = 0x80088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000000
FF1 = 0x4000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x20
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x800
EPIOCGPARAMS = 0x40088a02
EPIOCSPARAMS = 0x80088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000000
FF1 = 0x4000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x20
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x800
EPIOCGPARAMS = 0x40088a02
EPIOCSPARAMS = 0x80088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000000
FF1 = 0x4000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x800
EPIOCGPARAMS = 0x80088a02
EPIOCSPARAMS = 0x40088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -78,6 +78,8 @@ const (
ECHOPRT = 0x400
EFD_CLOEXEC = 0x80000
EFD_NONBLOCK = 0x800
EPIOCGPARAMS = 0x80088a02
EPIOCSPARAMS = 0x40088a01
EPOLL_CLOEXEC = 0x80000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -82,6 +82,8 @@ const (
EFD_CLOEXEC = 0x400000
EFD_NONBLOCK = 0x4000
EMT_TAGOVF = 0x1
EPIOCGPARAMS = 0x40088a02
EPIOCSPARAMS = 0x80088a01
EPOLL_CLOEXEC = 0x400000
EXTPROC = 0x10000
FF1 = 0x8000

View File

@ -740,6 +740,54 @@ func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func renamexNp(from string, to string, flag uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(from)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(to)
if err != nil {
return
}
_, _, e1 := syscall_syscall(libc_renamex_np_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_renamex_np_trampoline_addr uintptr
//go:cgo_import_dynamic libc_renamex_np renamex_np "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func renameatxNp(fromfd int, from string, tofd int, to string, flag uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(from)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(to)
if err != nil {
return
}
_, _, e1 := syscall_syscall6(libc_renameatx_np_trampoline_addr, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), uintptr(flag), 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_renameatx_np_trampoline_addr uintptr
//go:cgo_import_dynamic libc_renameatx_np renameatx_np "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {

View File

@ -223,6 +223,16 @@ TEXT libc_ioctl_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_ioctl_trampoline_addr(SB), RODATA, $8
DATA ·libc_ioctl_trampoline_addr(SB)/8, $libc_ioctl_trampoline<>(SB)
TEXT libc_renamex_np_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_renamex_np(SB)
GLOBL ·libc_renamex_np_trampoline_addr(SB), RODATA, $8
DATA ·libc_renamex_np_trampoline_addr(SB)/8, $libc_renamex_np_trampoline<>(SB)
TEXT libc_renameatx_np_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_renameatx_np(SB)
GLOBL ·libc_renameatx_np_trampoline_addr(SB), RODATA, $8
DATA ·libc_renameatx_np_trampoline_addr(SB)/8, $libc_renameatx_np_trampoline<>(SB)
TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_sysctl(SB)
GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8

View File

@ -740,6 +740,54 @@ func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func renamexNp(from string, to string, flag uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(from)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(to)
if err != nil {
return
}
_, _, e1 := syscall_syscall(libc_renamex_np_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_renamex_np_trampoline_addr uintptr
//go:cgo_import_dynamic libc_renamex_np renamex_np "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func renameatxNp(fromfd int, from string, tofd int, to string, flag uint32) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(from)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(to)
if err != nil {
return
}
_, _, e1 := syscall_syscall6(libc_renameatx_np_trampoline_addr, uintptr(fromfd), uintptr(unsafe.Pointer(_p0)), uintptr(tofd), uintptr(unsafe.Pointer(_p1)), uintptr(flag), 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_renameatx_np_trampoline_addr uintptr
//go:cgo_import_dynamic libc_renameatx_np renameatx_np "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {

View File

@ -223,6 +223,16 @@ TEXT libc_ioctl_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_ioctl_trampoline_addr(SB), RODATA, $8
DATA ·libc_ioctl_trampoline_addr(SB)/8, $libc_ioctl_trampoline<>(SB)
TEXT libc_renamex_np_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_renamex_np(SB)
GLOBL ·libc_renamex_np_trampoline_addr(SB), RODATA, $8
DATA ·libc_renamex_np_trampoline_addr(SB)/8, $libc_renamex_np_trampoline<>(SB)
TEXT libc_renameatx_np_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_renameatx_np(SB)
GLOBL ·libc_renameatx_np_trampoline_addr(SB), RODATA, $8
DATA ·libc_renameatx_np_trampoline_addr(SB)/8, $libc_renameatx_np_trampoline<>(SB)
TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_sysctl(SB)
GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8

View File

@ -2229,3 +2229,19 @@ func Cachestat(fd uint, crange *CachestatRange, cstat *Cachestat_t, flags uint)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Mseal(b []byte, flags uint) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MSEAL, uintptr(_p0), uintptr(len(b)), uintptr(flags))
if e1 != 0 {
err = errnoErr(e1)
}
return
}

View File

@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(fsType)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(dir)
if err != nil {
return
}
_, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_mount_trampoline_addr uintptr
//go:cgo_import_dynamic libc_mount mount "libc.so"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
if e1 != 0 {

View File

@ -463,6 +463,11 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $4
DATA ·libc_mknodat_trampoline_addr(SB)/4, $libc_mknodat_trampoline<>(SB)
TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_mount(SB)
GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $4
DATA ·libc_mount_trampoline_addr(SB)/4, $libc_mount_trampoline<>(SB)
TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_nanosleep(SB)
GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $4

View File

@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(fsType)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(dir)
if err != nil {
return
}
_, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_mount_trampoline_addr uintptr
//go:cgo_import_dynamic libc_mount mount "libc.so"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
if e1 != 0 {

View File

@ -463,6 +463,11 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $8
DATA ·libc_mknodat_trampoline_addr(SB)/8, $libc_mknodat_trampoline<>(SB)
TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_mount(SB)
GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $8
DATA ·libc_mount_trampoline_addr(SB)/8, $libc_mount_trampoline<>(SB)
TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_nanosleep(SB)
GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $8

View File

@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(fsType)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(dir)
if err != nil {
return
}
_, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_mount_trampoline_addr uintptr
//go:cgo_import_dynamic libc_mount mount "libc.so"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
if e1 != 0 {

View File

@ -463,6 +463,11 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $4
DATA ·libc_mknodat_trampoline_addr(SB)/4, $libc_mknodat_trampoline<>(SB)
TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_mount(SB)
GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $4
DATA ·libc_mount_trampoline_addr(SB)/4, $libc_mount_trampoline<>(SB)
TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_nanosleep(SB)
GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $4

View File

@ -1493,6 +1493,30 @@ var libc_mknodat_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(fsType)
if err != nil {
return
}
var _p1 *byte
_p1, err = BytePtrFromString(dir)
if err != nil {
return
}
_, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_mount_trampoline_addr uintptr
//go:cgo_import_dynamic libc_mount mount "libc.so"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := syscall_syscall(libc_nanosleep_trampoline_addr, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
if e1 != 0 {

View File

@ -463,6 +463,11 @@ TEXT libc_mknodat_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_mknodat_trampoline_addr(SB), RODATA, $8
DATA ·libc_mknodat_trampoline_addr(SB)/8, $libc_mknodat_trampoline<>(SB)
TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_mount(SB)
GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $8
DATA ·libc_mount_trampoline_addr(SB)/8, $libc_mount_trampoline<>(SB)
TEXT libc_nanosleep_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_nanosleep(SB)
GLOBL ·libc_nanosleep_trampoline_addr(SB), RODATA, $8

Some files were not shown because too many files have changed in this diff Show More