chore(deps): bump github.com/moby/buildkit from 0.12.5 to 0.13.0 (#3072)
Bumps [github.com/moby/buildkit](https://github.com/moby/buildkit) from 0.12.5 to 0.13.0. - [Release notes](https://github.com/moby/buildkit/releases) - [Commits](https://github.com/moby/buildkit/compare/v0.12.5...v0.13.0) --- updated-dependencies: - dependency-name: github.com/moby/buildkit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
parent
5590f9cb33
commit
fcc800fabf
28
go.mod
28
go.mod
|
|
@ -22,7 +22,7 @@ require (
|
|||
github.com/google/slowjam v1.1.0
|
||||
github.com/karrick/godirwalk v1.16.1
|
||||
github.com/minio/highwayhash v1.0.2
|
||||
github.com/moby/buildkit v0.12.5
|
||||
github.com/moby/buildkit v0.13.0
|
||||
github.com/otiai10/copy v1.14.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
|
|
@ -80,15 +80,15 @@ require (
|
|||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cilium/ebpf v0.9.1 // indirect
|
||||
github.com/containerd/continuity v0.4.2 // indirect
|
||||
github.com/containerd/continuity v0.4.3 // indirect
|
||||
github.com/containerd/fifo v1.1.0 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/docker/cli v24.0.7+incompatible // indirect
|
||||
github.com/docker/cli v25.0.3+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.0 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
|
|
@ -109,28 +109,28 @@ require (
|
|||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.17.2 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0
|
||||
github.com/moby/sys/mount v0.3.3 // indirect
|
||||
github.com/moby/sys/mountinfo v0.6.2 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.1 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.0
|
||||
github.com/moby/sys/symlink v0.2.0 // indirect
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
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
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.1 // indirect
|
||||
github.com/vbatts/tar-split v0.11.3 // indirect
|
||||
github.com/vbatts/tar-split v0.11.5 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.5.6 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
|
|
|
|||
69
go.sum
69
go.sum
|
|
@ -55,7 +55,6 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp
|
|||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/GoogleCloudPlatform/docker-credential-gcr/v2 v2.1.22 h1:HevuUpLsTedep2D6wnIp6AAJbVgP0BiVxaMt3HXeOyA=
|
||||
github.com/GoogleCloudPlatform/docker-credential-gcr/v2 v2.1.22/go.mod h1:nzCpg7DFIIkQIZB3mdUPXVvqQ5f/GahA6xgWXTjnK7w=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
|
|
@ -149,14 +148,14 @@ github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKk
|
|||
github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE=
|
||||
github.com/containerd/containerd v1.7.13 h1:wPYKIeGMN8vaggSKuV1X0wZulpMz4CrgEsZdaCyB6Is=
|
||||
github.com/containerd/containerd v1.7.13/go.mod h1:zT3up6yTRfEUa6+GsITYIJNgSVL9NQ4x4h1RPzk0Wu4=
|
||||
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
||||
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||
github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8=
|
||||
github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||
github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
|
||||
github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
|
||||
github.com/containerd/ttrpc v1.2.2 h1:9vqZr0pxwOF5koz6N0N3kJ0zDHokrcPxIR/ZR2YFtOs=
|
||||
github.com/containerd/ttrpc v1.2.2/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak=
|
||||
github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4=
|
||||
|
|
@ -164,7 +163,6 @@ github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3H
|
|||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
|
|
@ -180,16 +178,16 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK
|
|||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg=
|
||||
github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v25.0.3+incompatible h1:KLeNs7zws74oFuVhgZQ5ONGZiXUUdgsdy6/EsX/6284=
|
||||
github.com/docker/cli v25.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v25.0.4+incompatible h1:XITZTrq+52tZyZxUOtFIahUf3aH367FLxJzt9vZeAF8=
|
||||
github.com/docker/docker v25.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
|
||||
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
||||
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||
|
|
@ -258,7 +256,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||
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=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
|
|
@ -335,8 +332,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF
|
|||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
||||
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
|
|
@ -359,8 +356,8 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
|
|||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/buildkit v0.12.5 h1:RNHH1l3HDhYyZafr5EgstEu8aGNCwyfvMtrQDtjH9T0=
|
||||
github.com/moby/buildkit v0.12.5/go.mod h1:YGwjA2loqyiYfZeEo8FtI7z4x5XponAaIWsWcSjWwso=
|
||||
github.com/moby/buildkit v0.13.0 h1:reVR1Y+rbNIUQ9jf0Q1YZVH5a/nhOixZsl+HJ9qQEGI=
|
||||
github.com/moby/buildkit v0.13.0/go.mod h1:aNmNQKLBFYAOFuzQjR3VA27/FijlvtBD1pjNwTSN37k=
|
||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||
|
|
@ -369,8 +366,9 @@ github.com/moby/swarmkit/v2 v2.0.0-20230315203717-e28e8ba9bc83 h1:jUbNDiRMDXd2rY
|
|||
github.com/moby/swarmkit/v2 v2.0.0-20230315203717-e28e8ba9bc83/go.mod h1:GvjR7mC8YuUd9Mq44lrrIZPaXyKPAGEUMBpAQzaj3dI=
|
||||
github.com/moby/sys/mount v0.3.3 h1:fX1SVkXFJ47XWDoeFW4Sq7PdQJnV2QIDZAqjNqgEjUs=
|
||||
github.com/moby/sys/mount v0.3.3/go.mod h1:PBaEorSNTLG5t/+4EgukEQVlAvVEc6ZjTySwKdqp5K0=
|
||||
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
|
||||
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
||||
github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
|
||||
github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
||||
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
||||
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||
github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI=
|
||||
|
|
@ -379,8 +377,8 @@ github.com/moby/sys/symlink v0.2.0 h1:tk1rOM+Ljp0nFmfOIBtlV3rTDlWOwFRhjEeAhZB0nZ
|
|||
github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs=
|
||||
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
|
||||
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
|
|
@ -392,8 +390,8 @@ github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
|||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
|
||||
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
|
||||
|
|
@ -418,23 +416,23 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH
|
|||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
|
|
@ -447,7 +445,6 @@ github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NF
|
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
|
||||
|
|
@ -482,9 +479,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
|
|||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ=
|
||||
github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
|
||||
github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
|
||||
github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck=
|
||||
github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY=
|
||||
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
|
||||
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
|
@ -502,10 +498,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 h1:doUP+Ex
|
|||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA=
|
||||
go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E=
|
||||
go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
|
||||
go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo=
|
||||
go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo=
|
||||
go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw=
|
||||
|
|
@ -604,7 +600,6 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
|
|||
|
|
@ -103,11 +103,6 @@ func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) er
|
|||
}
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read %s: %w", src, err)
|
||||
}
|
||||
|
||||
if err := copyFileInfo(stat, src, dst); err != nil {
|
||||
return fmt.Errorf("failed to copy file info for %s: %w", dst, err)
|
||||
}
|
||||
|
|
@ -116,7 +111,15 @@ func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) er
|
|||
return fmt.Errorf("failed to copy xattrs: %w", err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
dr := &dirReader{f: f}
|
||||
|
||||
handleEntry := func(entry os.DirEntry) error {
|
||||
source := filepath.Join(src, entry.Name())
|
||||
target := filepath.Join(dst, entry.Name())
|
||||
|
||||
|
|
@ -130,7 +133,7 @@ func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) er
|
|||
if err := copyDirectory(target, source, inodes, o); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
return nil
|
||||
case (fileInfo.Mode() & os.ModeType) == 0:
|
||||
link, err := getLinkSource(target, fileInfo, inodes)
|
||||
if err != nil {
|
||||
|
|
@ -159,7 +162,7 @@ func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) er
|
|||
}
|
||||
default:
|
||||
logrus.Warnf("unsupported mode: %s: %s", source, fileInfo.Mode())
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := copyFileInfo(fileInfo, source, target); err != nil {
|
||||
|
|
@ -169,9 +172,20 @@ func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) er
|
|||
if err := copyXAttrs(target, source, o.xex, o.xeh); err != nil {
|
||||
return fmt.Errorf("failed to copy xattrs: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
for {
|
||||
entry := dr.Next()
|
||||
if entry == nil {
|
||||
break
|
||||
}
|
||||
|
||||
if err := handleEntry(entry); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return dr.Err()
|
||||
}
|
||||
|
||||
// CopyFile copies the source file to the target.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type dirReader struct {
|
||||
buf []os.DirEntry
|
||||
f *os.File
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *dirReader) Next() os.DirEntry {
|
||||
if len(r.buf) == 0 {
|
||||
infos, err := r.f.ReadDir(32)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
r.err = err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
r.buf = infos
|
||||
}
|
||||
|
||||
if len(r.buf) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := r.buf[0]
|
||||
r.buf[0] = nil
|
||||
r.buf = r.buf[1:]
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *dirReader) Err() error {
|
||||
return r.err
|
||||
}
|
||||
|
|
@ -436,9 +436,8 @@ func importTar(in io.ReaderAt) (*tarFile, error) {
|
|||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else {
|
||||
return nil, fmt.Errorf("failed to parse tar file, %w", err)
|
||||
}
|
||||
return nil, fmt.Errorf("failed to parse tar file, %w", err)
|
||||
}
|
||||
switch cleanEntryName(h.Name) {
|
||||
case PrefetchLandmark, NoPrefetchLandmark:
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
# This file lists all contributors to the repository.
|
||||
# See scripts/docs/generate-authors.sh to make modifications.
|
||||
|
||||
A. Lester Buck III <github-reg@nbolt.com>
|
||||
Aanand Prasad <aanand.prasad@gmail.com>
|
||||
Aaron L. Xu <liker.xu@foxmail.com>
|
||||
Aaron Lehmann <alehmann@netflix.com>
|
||||
|
|
@ -16,6 +17,7 @@ Adolfo Ochagavía <aochagavia92@gmail.com>
|
|||
Adrian Plata <adrian.plata@docker.com>
|
||||
Adrien Duermael <adrien@duermael.com>
|
||||
Adrien Folie <folie.adrien@gmail.com>
|
||||
Adyanth Hosavalike <ahosavalike@ucsd.edu>
|
||||
Ahmet Alp Balkan <ahmetb@microsoft.com>
|
||||
Aidan Feldman <aidan.feldman@gmail.com>
|
||||
Aidan Hobson Sayers <aidanhs@cantab.net>
|
||||
|
|
@ -26,7 +28,7 @@ Akim Demaille <akim.demaille@docker.com>
|
|||
Alan Thompson <cloojure@gmail.com>
|
||||
Albert Callarisa <shark234@gmail.com>
|
||||
Alberto Roura <mail@albertoroura.com>
|
||||
Albin Kerouanton <albin@akerouanton.name>
|
||||
Albin Kerouanton <albinker@gmail.com>
|
||||
Aleksa Sarai <asarai@suse.de>
|
||||
Aleksander Piotrowski <apiotrowski312@gmail.com>
|
||||
Alessandro Boch <aboch@tetrationanalytics.com>
|
||||
|
|
@ -34,6 +36,7 @@ Alex Couture-Beil <alex@earthly.dev>
|
|||
Alex Mavrogiannis <alex.mavrogiannis@docker.com>
|
||||
Alex Mayer <amayer5125@gmail.com>
|
||||
Alexander Boyd <alex@opengroove.org>
|
||||
Alexander Chneerov <achneerov@gmail.com>
|
||||
Alexander Larsson <alexl@redhat.com>
|
||||
Alexander Morozov <lk4d4math@gmail.com>
|
||||
Alexander Ryabov <i@sepa.spb.ru>
|
||||
|
|
@ -41,6 +44,7 @@ Alexandre González <agonzalezro@gmail.com>
|
|||
Alexey Igrychev <alexey.igrychev@flant.com>
|
||||
Alexis Couvreur <alexiscouvreur.pro@gmail.com>
|
||||
Alfred Landrum <alfred.landrum@docker.com>
|
||||
Ali Rostami <rostami.ali@gmail.com>
|
||||
Alicia Lauerman <alicia@eta.im>
|
||||
Allen Sun <allensun.shl@alibaba-inc.com>
|
||||
Alvin Deng <alvin.q.deng@utexas.edu>
|
||||
|
|
@ -79,7 +83,9 @@ Arko Dasgupta <arko@tetrate.io>
|
|||
Arnaud Porterie <icecrime@gmail.com>
|
||||
Arnaud Rebillout <elboulangero@gmail.com>
|
||||
Arthur Peka <arthur.peka@outlook.com>
|
||||
Ashly Mathew <ashly.mathew@sap.com>
|
||||
Ashwini Oruganti <ashwini.oruganti@gmail.com>
|
||||
Aslam Ahemad <aslamahemad@gmail.com>
|
||||
Azat Khuyiyakhmetov <shadow_uz@mail.ru>
|
||||
Bardia Keyoumarsi <bkeyouma@ucsc.edu>
|
||||
Barnaby Gray <barnaby@pickle.me.uk>
|
||||
|
|
@ -98,7 +104,9 @@ Bill Wang <ozbillwang@gmail.com>
|
|||
Bin Liu <liubin0329@gmail.com>
|
||||
Bingshen Wang <bingshen.wbs@alibaba-inc.com>
|
||||
Bishal Das <bishalhnj127@gmail.com>
|
||||
Bjorn Neergaard <bjorn.neergaard@docker.com>
|
||||
Boaz Shuster <ripcurld.github@gmail.com>
|
||||
Boban Acimovic <boban.acimovic@gmail.com>
|
||||
Bogdan Anton <contact@bogdananton.ro>
|
||||
Boris Pruessmann <boris@pruessmann.org>
|
||||
Brad Baker <brad@brad.fi>
|
||||
|
|
@ -109,6 +117,7 @@ Brent Salisbury <brent.salisbury@docker.com>
|
|||
Bret Fisher <bret@bretfisher.com>
|
||||
Brian (bex) Exelbierd <bexelbie@redhat.com>
|
||||
Brian Goff <cpuguy83@gmail.com>
|
||||
Brian Tracy <brian.tracy33@gmail.com>
|
||||
Brian Wieder <brian@4wieders.com>
|
||||
Bruno Sousa <bruno.sousa@docker.com>
|
||||
Bryan Bess <squarejaw@bsbess.com>
|
||||
|
|
@ -136,6 +145,7 @@ Chen Chuanliang <chen.chuanliang@zte.com.cn>
|
|||
Chen Hanxiao <chenhanxiao@cn.fujitsu.com>
|
||||
Chen Mingjie <chenmingjie0828@163.com>
|
||||
Chen Qiu <cheney-90@hotmail.com>
|
||||
Chris Chinchilla <chris@chrischinchilla.com>
|
||||
Chris Couzens <ccouzens@gmail.com>
|
||||
Chris Gavin <chris@chrisgavin.me>
|
||||
Chris Gibson <chris@chrisg.io>
|
||||
|
|
@ -163,6 +173,8 @@ Conner Crosby <conner@cavcrosby.tech>
|
|||
Corey Farrell <git@cfware.com>
|
||||
Corey Quon <corey.quon@docker.com>
|
||||
Cory Bennet <cbennett@netflix.com>
|
||||
Cory Snider <csnider@mirantis.com>
|
||||
Craig Osterhout <craig.osterhout@docker.com>
|
||||
Craig Wilhite <crwilhit@microsoft.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com>
|
||||
Daehyeok Mun <daehyeok@gmail.com>
|
||||
|
|
@ -171,6 +183,7 @@ Daisuke Ito <itodaisuke00@gmail.com>
|
|||
dalanlan <dalanlan925@gmail.com>
|
||||
Damien Nadé <github@livna.org>
|
||||
Dan Cotora <dan@bluevision.ro>
|
||||
Danial Gharib <danial.mail.gh@gmail.com>
|
||||
Daniel Artine <daniel.artine@ufrj.br>
|
||||
Daniel Cassidy <mail@danielcassidy.me.uk>
|
||||
Daniel Dao <dqminh@cloudflare.com>
|
||||
|
|
@ -210,6 +223,7 @@ Denis Defreyne <denis@soundcloud.com>
|
|||
Denis Gladkikh <denis@gladkikh.email>
|
||||
Denis Ollier <larchunix@users.noreply.github.com>
|
||||
Dennis Docter <dennis@d23.nl>
|
||||
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
||||
Derek McGowan <derek@mcg.dev>
|
||||
Des Preston <despreston@gmail.com>
|
||||
Deshi Xiao <dxiao@redhat.com>
|
||||
|
|
@ -232,11 +246,13 @@ DongGeon Lee <secmatth1996@gmail.com>
|
|||
Doug Davis <dug@us.ibm.com>
|
||||
Drew Erny <derny@mirantis.com>
|
||||
Ed Costello <epc@epcostello.com>
|
||||
Ed Morley <501702+edmorley@users.noreply.github.com>
|
||||
Elango Sivanandam <elango.siva@docker.com>
|
||||
Eli Uriegas <eli.uriegas@docker.com>
|
||||
Eli Uriegas <seemethere101@gmail.com>
|
||||
Elias Faxö <elias.faxo@tre.se>
|
||||
Elliot Luo <956941328@qq.com>
|
||||
Eric Bode <eric.bode@foundries.io>
|
||||
Eric Curtin <ericcurtin17@gmail.com>
|
||||
Eric Engestrom <eric@engestrom.ch>
|
||||
Eric G. Noriega <enoriega@vizuri.com>
|
||||
|
|
@ -254,6 +270,7 @@ Eugene Yakubovich <eugene.yakubovich@coreos.com>
|
|||
Evan Allrich <evan@unguku.com>
|
||||
Evan Hazlett <ejhazlett@gmail.com>
|
||||
Evan Krall <krall@yelp.com>
|
||||
Evan Lezar <elezar@nvidia.com>
|
||||
Evelyn Xu <evelynhsu21@gmail.com>
|
||||
Everett Toews <everett.toews@rackspace.com>
|
||||
Fabio Falci <fabiofalci@gmail.com>
|
||||
|
|
@ -275,6 +292,7 @@ Frederik Nordahl Jul Sabroe <frederikns@gmail.com>
|
|||
Frieder Bluemle <frieder.bluemle@gmail.com>
|
||||
Gabriel Gore <gabgore@cisco.com>
|
||||
Gabriel Nicolas Avellaneda <avellaneda.gabriel@gmail.com>
|
||||
Gabriela Georgieva <gabriela.georgieva@docker.com>
|
||||
Gaetan de Villele <gdevillele@gmail.com>
|
||||
Gang Qiao <qiaohai8866@gmail.com>
|
||||
Gary Schaetz <gary@schaetzkc.com>
|
||||
|
|
@ -288,6 +306,7 @@ Gleb Stsenov <gleb.stsenov@gmail.com>
|
|||
Goksu Toprak <goksu.toprak@docker.com>
|
||||
Gou Rao <gou@portworx.com>
|
||||
Govind Rai <raigovind93@gmail.com>
|
||||
Graeme Wiebe <graeme.wiebe@gmail.com>
|
||||
Grant Reaber <grant.reaber@gmail.com>
|
||||
Greg Pflaum <gpflaum@users.noreply.github.com>
|
||||
Gsealy <jiaojingwei1001@hotmail.com>
|
||||
|
|
@ -311,6 +330,7 @@ Hernan Garcia <hernandanielg@gmail.com>
|
|||
Hongbin Lu <hongbin034@gmail.com>
|
||||
Hu Keping <hukeping@huawei.com>
|
||||
Huayi Zhang <irachex@gmail.com>
|
||||
Hugo Chastel <Hugo-C@users.noreply.github.com>
|
||||
Hugo Gabriel Eyherabide <hugogabriel.eyherabide@gmail.com>
|
||||
huqun <huqun@zju.edu.cn>
|
||||
Huu Nguyen <huu@prismskylabs.com>
|
||||
|
|
@ -329,9 +349,12 @@ Ivan Grund <ivan.grund@gmail.com>
|
|||
Ivan Markin <sw@nogoegst.net>
|
||||
Jacob Atzen <jacob@jacobatzen.dk>
|
||||
Jacob Tomlinson <jacob@tom.linson.uk>
|
||||
Jacopo Rigoli <rigoli.jacopo@gmail.com>
|
||||
Jaivish Kothari <janonymous.codevulture@gmail.com>
|
||||
Jake Lambert <jake.lambert@volusion.com>
|
||||
Jake Sanders <jsand@google.com>
|
||||
Jake Stokes <contactjake@developerjake.com>
|
||||
Jakub Panek <me@panekj.dev>
|
||||
James Nesbitt <james.nesbitt@wunderkraut.com>
|
||||
James Turnbull <james@lovedthanlost.net>
|
||||
Jamie Hannaford <jamie@limetree.org>
|
||||
|
|
@ -408,10 +431,12 @@ Josh Chorlton <jchorlton@gmail.com>
|
|||
Josh Hawn <josh.hawn@docker.com>
|
||||
Josh Horwitz <horwitz@addthis.com>
|
||||
Josh Soref <jsoref@gmail.com>
|
||||
Julian <gitea+julian@ic.thejulian.uk>
|
||||
Julien Barbier <write0@gmail.com>
|
||||
Julien Kassar <github@kassisol.com>
|
||||
Julien Maitrehenry <julien.maitrehenry@me.com>
|
||||
Justas Brazauskas <brazauskasjustas@gmail.com>
|
||||
Justin Chadwell <me@jedevc.com>
|
||||
Justin Cormack <justin.cormack@docker.com>
|
||||
Justin Simonelis <justin.p.simonelis@gmail.com>
|
||||
Justyn Temme <justyntemme@gmail.com>
|
||||
|
|
@ -434,7 +459,7 @@ Kelton Bassingthwaite <KeltonBassingthwaite@gmail.com>
|
|||
Ken Cochrane <kencochrane@gmail.com>
|
||||
Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com>
|
||||
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
||||
Kevin Alvarez <crazy-max@users.noreply.github.com>
|
||||
Kevin Alvarez <github@crazymax.dev>
|
||||
Kevin Burke <kev@inburke.com>
|
||||
Kevin Feyrer <kevin.feyrer@btinternet.com>
|
||||
Kevin Kern <kaiwentan@harmonycloud.cn>
|
||||
|
|
@ -454,6 +479,7 @@ Kyle Mitofsky <Kylemit@gmail.com>
|
|||
Lachlan Cooper <lachlancooper@gmail.com>
|
||||
Lai Jiangshan <jiangshanlai@gmail.com>
|
||||
Lars Kellogg-Stedman <lars@redhat.com>
|
||||
Laura Brehm <laurabrehm@hey.com>
|
||||
Laura Frank <ljfrank@gmail.com>
|
||||
Laurent Erignoux <lerignoux@gmail.com>
|
||||
Lee Gaines <eightlimbed@gmail.com>
|
||||
|
|
@ -462,10 +488,10 @@ Lennie <github@consolejunkie.net>
|
|||
Leo Gallucci <elgalu3@gmail.com>
|
||||
Leonid Skorospelov <leosko94@gmail.com>
|
||||
Lewis Daly <lewisdaly@me.com>
|
||||
Li Fu Bang <lifubang@acmcoder.com>
|
||||
Li Yi <denverdino@gmail.com>
|
||||
Li Yi <weiyuan.yl@alibaba-inc.com>
|
||||
Liang-Chi Hsieh <viirya@gmail.com>
|
||||
Lifubang <lifubang@acmcoder.com>
|
||||
Lihua Tang <lhtang@alauda.io>
|
||||
Lily Guo <lily.guo@docker.com>
|
||||
Lin Lu <doraalin@163.com>
|
||||
|
|
@ -480,6 +506,7 @@ Louis Opter <kalessin@kalessin.fr>
|
|||
Luca Favatella <luca.favatella@erlang-solutions.com>
|
||||
Luca Marturana <lucamarturana@gmail.com>
|
||||
Lucas Chan <lucas-github@lucaschan.com>
|
||||
Luis Henrique Mulinari <luis.mulinari@gmail.com>
|
||||
Luka Hartwig <mail@lukahartwig.de>
|
||||
Lukas Heeren <lukas-heeren@hotmail.com>
|
||||
Lukasz Zajaczkowski <Lukasz.Zajaczkowski@ts.fujitsu.com>
|
||||
|
|
@ -498,6 +525,7 @@ mapk0y <mapk0y@gmail.com>
|
|||
Marc Bihlmaier <marc.bihlmaier@reddoxx.com>
|
||||
Marc Cornellà <hello@mcornella.com>
|
||||
Marco Mariani <marco.mariani@alterway.fr>
|
||||
Marco Spiess <marco.spiess@hotmail.de>
|
||||
Marco Vedovati <mvedovati@suse.com>
|
||||
Marcus Martins <marcus@docker.com>
|
||||
Marianna Tessel <mtesselh@gmail.com>
|
||||
|
|
@ -522,6 +550,7 @@ Max Shytikov <mshytikov@gmail.com>
|
|||
Maxime Petazzoni <max@signalfuse.com>
|
||||
Maximillian Fan Xavier <maximillianfx@gmail.com>
|
||||
Mei ChunTao <mei.chuntao@zte.com.cn>
|
||||
Melroy van den Berg <melroy@melroy.org>
|
||||
Metal <2466052+tedhexaflow@users.noreply.github.com>
|
||||
Micah Zoltu <micah@newrelic.com>
|
||||
Michael A. Smith <michael@smith-li.com>
|
||||
|
|
@ -593,6 +622,7 @@ Nishant Totla <nishanttotla@gmail.com>
|
|||
NIWA Hideyuki <niwa.niwa@nifty.ne.jp>
|
||||
Noah Treuhaft <noah.treuhaft@docker.com>
|
||||
O.S. Tezer <ostezer@gmail.com>
|
||||
Oded Arbel <oded@geek.co.il>
|
||||
Odin Ugedal <odin@ugedal.com>
|
||||
ohmystack <jun.jiang02@ele.me>
|
||||
OKA Naoya <git@okanaoya.com>
|
||||
|
|
@ -604,19 +634,21 @@ Otto Kekäläinen <otto@seravo.fi>
|
|||
Ovidio Mallo <ovidio.mallo@gmail.com>
|
||||
Pascal Borreli <pascal@borreli.com>
|
||||
Patrick Böänziger <patrick.baenziger@bsi-software.com>
|
||||
Patrick Daigle <114765035+pdaig@users.noreply.github.com>
|
||||
Patrick Hemmer <patrick.hemmer@gmail.com>
|
||||
Patrick Lang <plang@microsoft.com>
|
||||
Paul <paul9869@gmail.com>
|
||||
Paul Kehrer <paul.l.kehrer@gmail.com>
|
||||
Paul Lietar <paul@lietar.net>
|
||||
Paul Mulders <justinkb@gmail.com>
|
||||
Paul Seyfert <pseyfert.mathphys@gmail.com>
|
||||
Paul Weaver <pauweave@cisco.com>
|
||||
Pavel Pospisil <pospispa@gmail.com>
|
||||
Paweł Gronowski <pawel.gronowski@docker.com>
|
||||
Paweł Pokrywka <pepawel@users.noreply.github.com>
|
||||
Paweł Szczekutowicz <pszczekutowicz@gmail.com>
|
||||
Peeyush Gupta <gpeeyush@linux.vnet.ibm.com>
|
||||
Per Lundberg <per.lundberg@ecraft.com>
|
||||
Per Lundberg <perlun@gmail.com>
|
||||
Peter Dave Hello <hsu@peterdavehello.org>
|
||||
Peter Edge <peter.edge@gmail.com>
|
||||
Peter Hsu <shhsu@microsoft.com>
|
||||
|
|
@ -639,6 +671,7 @@ Preston Cowley <preston.cowley@sony.com>
|
|||
Pure White <daniel48@126.com>
|
||||
Qiang Huang <h.huangqiang@huawei.com>
|
||||
Qinglan Peng <qinglanpeng@zju.edu.cn>
|
||||
QQ喵 <gqqnb2005@gmail.com>
|
||||
qudongfang <qudongfang@gmail.com>
|
||||
Raghavendra K T <raghavendra.kt@linux.vnet.ibm.com>
|
||||
Rahul Kadyan <hi@znck.me>
|
||||
|
|
@ -657,6 +690,7 @@ Rick Wieman <git@rickw.nl>
|
|||
Ritesh H Shukla <sritesh@vmware.com>
|
||||
Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
|
||||
Rob Gulewich <rgulewich@netflix.com>
|
||||
Rob Murray <rob.murray@docker.com>
|
||||
Robert Wallis <smilingrob@gmail.com>
|
||||
Robin Naundorf <r.naundorf@fh-muenster.de>
|
||||
Robin Speekenbrink <robin@kingsquare.nl>
|
||||
|
|
@ -689,6 +723,7 @@ Sandro Jäckel <sandro.jaeckel@gmail.com>
|
|||
Santhosh Manohar <santhosh@docker.com>
|
||||
Sargun Dhillon <sargun@netflix.com>
|
||||
Saswat Bhattacharya <sas.saswat@gmail.com>
|
||||
Saurabh Kumar <saurabhkumar0184@gmail.com>
|
||||
Scott Brenner <scott@scottbrenner.me>
|
||||
Scott Collier <emailscottcollier@gmail.com>
|
||||
Sean Christopherson <sean.j.christopherson@intel.com>
|
||||
|
|
@ -788,6 +823,7 @@ uhayate <uhayate.gong@daocloud.io>
|
|||
Ulrich Bareth <ulrich.bareth@gmail.com>
|
||||
Ulysses Souza <ulysses.souza@docker.com>
|
||||
Umesh Yadav <umesh4257@gmail.com>
|
||||
Vaclav Struhar <struharv@gmail.com>
|
||||
Valentin Lorentz <progval+git@progval.net>
|
||||
Vardan Pogosian <vardan.pogosyan@gmail.com>
|
||||
Venkateswara Reddy Bukkasamudram <bukkasamudram@outlook.com>
|
||||
|
|
@ -795,6 +831,7 @@ Veres Lajos <vlajos@gmail.com>
|
|||
Victor Vieux <victor.vieux@docker.com>
|
||||
Victoria Bialas <victoria.bialas@docker.com>
|
||||
Viktor Stanchev <me@viktorstanchev.com>
|
||||
Ville Skyttä <ville.skytta@iki.fi>
|
||||
Vimal Raghubir <vraghubir0418@gmail.com>
|
||||
Vincent Batts <vbatts@redhat.com>
|
||||
Vincent Bernat <Vincent.Bernat@exoscale.ch>
|
||||
|
|
@ -831,6 +868,7 @@ Yong Tang <yong.tang.github@outlook.com>
|
|||
Yosef Fertel <yfertel@gmail.com>
|
||||
Yu Peng <yu.peng36@zte.com.cn>
|
||||
Yuan Sun <sunyuan3@huawei.com>
|
||||
Yucheng Wu <wyc123wyc@gmail.com>
|
||||
Yue Zhang <zy675793960@yeah.net>
|
||||
Yunxiang Huang <hyxqshk@vip.qq.com>
|
||||
Zachary Romero <zacromero3@gmail.com>
|
||||
|
|
|
|||
|
|
@ -16,32 +16,25 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// ConfigFileName is the name of config file
|
||||
// EnvOverrideConfigDir is the name of the environment variable that can be
|
||||
// used to override the location of the client configuration files (~/.docker).
|
||||
//
|
||||
// It takes priority over the default, but can be overridden by the "--config"
|
||||
// command line option.
|
||||
EnvOverrideConfigDir = "DOCKER_CONFIG"
|
||||
|
||||
// ConfigFileName is the name of the client configuration file inside the
|
||||
// config-directory.
|
||||
ConfigFileName = "config.json"
|
||||
configFileDir = ".docker"
|
||||
oldConfigfile = ".dockercfg" // Deprecated: remove once we stop printing deprecation warning
|
||||
contextsDir = "contexts"
|
||||
)
|
||||
|
||||
var (
|
||||
initConfigDir = new(sync.Once)
|
||||
configDir string
|
||||
homeDir string
|
||||
)
|
||||
|
||||
// resetHomeDir is used in testing to reset the "homeDir" package variable to
|
||||
// force re-lookup of the home directory between tests.
|
||||
func resetHomeDir() {
|
||||
homeDir = ""
|
||||
}
|
||||
|
||||
func getHomeDir() string {
|
||||
if homeDir == "" {
|
||||
homeDir = homedir.Get()
|
||||
}
|
||||
return homeDir
|
||||
}
|
||||
|
||||
// resetConfigDir is used in testing to reset the "configDir" package variable
|
||||
// and its sync.Once to force re-lookup between tests.
|
||||
func resetConfigDir() {
|
||||
|
|
@ -49,19 +42,14 @@ func resetConfigDir() {
|
|||
initConfigDir = new(sync.Once)
|
||||
}
|
||||
|
||||
func setConfigDir() {
|
||||
if configDir != "" {
|
||||
return
|
||||
}
|
||||
configDir = os.Getenv("DOCKER_CONFIG")
|
||||
if configDir == "" {
|
||||
configDir = filepath.Join(getHomeDir(), configFileDir)
|
||||
}
|
||||
}
|
||||
|
||||
// Dir returns the directory the configuration file is stored in
|
||||
func Dir() string {
|
||||
initConfigDir.Do(setConfigDir)
|
||||
initConfigDir.Do(func() {
|
||||
configDir = os.Getenv(EnvOverrideConfigDir)
|
||||
if configDir == "" {
|
||||
configDir = filepath.Join(homedir.Get(), configFileDir)
|
||||
}
|
||||
})
|
||||
return configDir
|
||||
}
|
||||
|
||||
|
|
@ -72,6 +60,8 @@ func ContextStoreDir() string {
|
|||
|
||||
// SetDir sets the directory the configuration file is stored in
|
||||
func SetDir(dir string) {
|
||||
// trigger the sync.Once to synchronise with Dir()
|
||||
initConfigDir.Do(func() {})
|
||||
configDir = filepath.Clean(dir)
|
||||
}
|
||||
|
||||
|
|
@ -96,55 +86,43 @@ func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
|
|||
|
||||
// Load reads the configuration files in the given directory, and sets up
|
||||
// the auth config information and returns values.
|
||||
// FIXME: use the internal golang config parser
|
||||
func Load(configDir string) (*configfile.ConfigFile, error) {
|
||||
cfg, _, err := load(configDir)
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
// TODO remove this temporary hack, which is used to warn about the deprecated ~/.dockercfg file
|
||||
// so we can remove the bool return value and collapse this back into `Load`
|
||||
func load(configDir string) (*configfile.ConfigFile, bool, error) {
|
||||
printLegacyFileWarning := false
|
||||
|
||||
if configDir == "" {
|
||||
configDir = Dir()
|
||||
}
|
||||
return load(configDir)
|
||||
}
|
||||
|
||||
func load(configDir string) (*configfile.ConfigFile, error) {
|
||||
filename := filepath.Join(configDir, ConfigFileName)
|
||||
configFile := configfile.New(filename)
|
||||
|
||||
// Try happy path first - latest config file
|
||||
if file, err := os.Open(filename); err == nil {
|
||||
defer file.Close()
|
||||
err = configFile.LoadFromReader(file)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, filename)
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
//
|
||||
// if file is there but we can't stat it for any reason other
|
||||
// than it doesn't exist then stop
|
||||
return configFile, nil
|
||||
}
|
||||
return configFile, printLegacyFileWarning, err
|
||||
} else if !os.IsNotExist(err) {
|
||||
// if file is there but we can't stat it for any reason other
|
||||
// than it doesn't exist then stop
|
||||
return configFile, printLegacyFileWarning, errors.Wrap(err, filename)
|
||||
return configFile, nil
|
||||
}
|
||||
|
||||
// Can't find latest config file so check for the old one
|
||||
filename = filepath.Join(getHomeDir(), oldConfigfile)
|
||||
if _, err := os.Stat(filename); err == nil {
|
||||
printLegacyFileWarning = true
|
||||
defer file.Close()
|
||||
err = configFile.LoadFromReader(file)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, filename)
|
||||
}
|
||||
return configFile, printLegacyFileWarning, nil
|
||||
return configFile, err
|
||||
}
|
||||
|
||||
// LoadDefaultConfigFile attempts to load the default config file and returns
|
||||
// an initialized ConfigFile struct if none is found.
|
||||
func LoadDefaultConfigFile(stderr io.Writer) *configfile.ConfigFile {
|
||||
configFile, printLegacyFileWarning, err := load(Dir())
|
||||
configFile, err := load(Dir())
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "WARNING: Error loading config file: %v\n", err)
|
||||
}
|
||||
if printLegacyFileWarning {
|
||||
_, _ = fmt.Fprintln(stderr, "WARNING: Support for the legacy ~/.dockercfg configuration file and file-format has been removed and the configuration file will be ignored")
|
||||
_, _ = fmt.Fprintf(stderr, "WARNING: Error loading config file: %v\n", err)
|
||||
}
|
||||
if !configFile.ContainsAuth() {
|
||||
configFile.CredentialsStore = credentials.DetectDefaultStore(configFile.CredentialsStore)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package configfile
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,22 @@
|
|||
package credentials
|
||||
|
||||
import (
|
||||
exec "golang.org/x/sys/execabs"
|
||||
)
|
||||
import "os/exec"
|
||||
|
||||
// DetectDefaultStore return the default credentials store for the platform if
|
||||
// the store executable is available.
|
||||
// no user-defined store is passed, and the store executable is available.
|
||||
func DetectDefaultStore(store string) string {
|
||||
platformDefault := defaultCredentialsStore()
|
||||
|
||||
// user defined or no default for platform
|
||||
if store != "" || platformDefault == "" {
|
||||
if store != "" {
|
||||
// use user-defined
|
||||
return store
|
||||
}
|
||||
|
||||
if _, err := exec.LookPath(remoteCredentialsPrefix + platformDefault); err == nil {
|
||||
return platformDefault
|
||||
platformDefault := defaultCredentialsStore()
|
||||
if platformDefault == "" {
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
|
||||
if _, err := exec.LookPath(remoteCredentialsPrefix + platformDefault); err != nil {
|
||||
return ""
|
||||
}
|
||||
return platformDefault
|
||||
}
|
||||
|
|
|
|||
1
vendor/github.com/docker/cli/cli/config/credentials/default_store_unsupported.go
generated
vendored
1
vendor/github.com/docker/cli/cli/config/credentials/default_store_unsupported.go
generated
vendored
|
|
@ -1,5 +1,4 @@
|
|||
//go:build !windows && !darwin && !linux
|
||||
// +build !windows,!darwin,!linux
|
||||
|
||||
package credentials
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ func (c *nativeStore) Get(serverAddress string) (types.AuthConfig, error) {
|
|||
auth.Username = creds.Username
|
||||
auth.IdentityToken = creds.IdentityToken
|
||||
auth.Password = creds.Password
|
||||
auth.ServerAddress = creds.ServerAddress
|
||||
|
||||
return auth, nil
|
||||
}
|
||||
|
|
@ -76,6 +77,9 @@ func (c *nativeStore) GetAll() (map[string]types.AuthConfig, error) {
|
|||
ac.Username = creds.Username
|
||||
ac.Password = creds.Password
|
||||
ac.IdentityToken = creds.IdentityToken
|
||||
if ac.ServerAddress == "" {
|
||||
ac.ServerAddress = creds.ServerAddress
|
||||
}
|
||||
authConfigs[registry] = ac
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,6 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// portSpecTemplate is the expected format for port specifications
|
||||
portSpecTemplate = "ip:hostPort:containerPort"
|
||||
)
|
||||
|
||||
// PortBinding represents a binding between a Host IP address and a Host Port
|
||||
type PortBinding struct {
|
||||
// HostIP is the host IP Address
|
||||
|
|
@ -158,48 +153,51 @@ type PortMapping struct {
|
|||
func splitParts(rawport string) (string, string, string) {
|
||||
parts := strings.Split(rawport, ":")
|
||||
n := len(parts)
|
||||
containerport := parts[n-1]
|
||||
containerPort := parts[n-1]
|
||||
|
||||
switch n {
|
||||
case 1:
|
||||
return "", "", containerport
|
||||
return "", "", containerPort
|
||||
case 2:
|
||||
return "", parts[0], containerport
|
||||
return "", parts[0], containerPort
|
||||
case 3:
|
||||
return parts[0], parts[1], containerport
|
||||
return parts[0], parts[1], containerPort
|
||||
default:
|
||||
return strings.Join(parts[:n-2], ":"), parts[n-2], containerport
|
||||
return strings.Join(parts[:n-2], ":"), parts[n-2], containerPort
|
||||
}
|
||||
}
|
||||
|
||||
// ParsePortSpec parses a port specification string into a slice of PortMappings
|
||||
func ParsePortSpec(rawPort string) ([]PortMapping, error) {
|
||||
var proto string
|
||||
rawIP, hostPort, containerPort := splitParts(rawPort)
|
||||
ip, hostPort, containerPort := splitParts(rawPort)
|
||||
proto, containerPort = SplitProtoPort(containerPort)
|
||||
|
||||
// Strip [] from IPV6 addresses
|
||||
ip, _, err := net.SplitHostPort(rawIP + ":")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid ip address %v: %s", rawIP, err)
|
||||
if ip != "" && ip[0] == '[' {
|
||||
// Strip [] from IPV6 addresses
|
||||
rawIP, _, err := net.SplitHostPort(ip + ":")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid IP address %v: %w", ip, err)
|
||||
}
|
||||
ip = rawIP
|
||||
}
|
||||
if ip != "" && net.ParseIP(ip) == nil {
|
||||
return nil, fmt.Errorf("Invalid ip address: %s", ip)
|
||||
return nil, fmt.Errorf("invalid IP address: %s", ip)
|
||||
}
|
||||
if containerPort == "" {
|
||||
return nil, fmt.Errorf("No port specified: %s<empty>", rawPort)
|
||||
return nil, fmt.Errorf("no port specified: %s<empty>", rawPort)
|
||||
}
|
||||
|
||||
startPort, endPort, err := ParsePortRange(containerPort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid containerPort: %s", containerPort)
|
||||
return nil, fmt.Errorf("invalid containerPort: %s", containerPort)
|
||||
}
|
||||
|
||||
var startHostPort, endHostPort uint64 = 0, 0
|
||||
if len(hostPort) > 0 {
|
||||
startHostPort, endHostPort, err = ParsePortRange(hostPort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid hostPort: %s", hostPort)
|
||||
return nil, fmt.Errorf("invalid hostPort: %s", hostPort)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,12 +206,12 @@ func ParsePortSpec(rawPort string) ([]PortMapping, error) {
|
|||
// In this case, use the host port range as the dynamic
|
||||
// host port range to allocate into.
|
||||
if endPort != startPort {
|
||||
return nil, fmt.Errorf("Invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort)
|
||||
return nil, fmt.Errorf("invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort)
|
||||
}
|
||||
}
|
||||
|
||||
if !validateProto(strings.ToLower(proto)) {
|
||||
return nil, fmt.Errorf("Invalid proto: %s", proto)
|
||||
return nil, fmt.Errorf("invalid proto: %s", proto)
|
||||
}
|
||||
|
||||
ports := []PortMapping{}
|
||||
|
|
|
|||
|
|
@ -6,34 +6,10 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// PartParser parses and validates the specified string (data) using the specified template
|
||||
// e.g. ip:public:private -> 192.168.0.1:80:8000
|
||||
// DEPRECATED: do not use, this function may be removed in a future version
|
||||
func PartParser(template, data string) (map[string]string, error) {
|
||||
// ip:public:private
|
||||
var (
|
||||
templateParts = strings.Split(template, ":")
|
||||
parts = strings.Split(data, ":")
|
||||
out = make(map[string]string, len(templateParts))
|
||||
)
|
||||
if len(parts) != len(templateParts) {
|
||||
return nil, fmt.Errorf("Invalid format to parse. %s should match template %s", data, template)
|
||||
}
|
||||
|
||||
for i, t := range templateParts {
|
||||
value := ""
|
||||
if len(parts) > i {
|
||||
value = parts[i]
|
||||
}
|
||||
out[t] = value
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ParsePortRange parses and validates the specified string as a port-range (8000-9000)
|
||||
func ParsePortRange(ports string) (uint64, uint64, error) {
|
||||
if ports == "" {
|
||||
return 0, 0, fmt.Errorf("Empty string specified for ports.")
|
||||
return 0, 0, fmt.Errorf("empty string specified for ports")
|
||||
}
|
||||
if !strings.Contains(ports, "-") {
|
||||
start, err := strconv.ParseUint(ports, 10, 16)
|
||||
|
|
@ -51,7 +27,7 @@ func ParsePortRange(ports string) (uint64, uint64, error) {
|
|||
return 0, 0, err
|
||||
}
|
||||
if end < start {
|
||||
return 0, 0, fmt.Errorf("Invalid range specified for the Port: %s", ports)
|
||||
return 0, 0, fmt.Errorf("invalid range specified for port: %s", ports)
|
||||
}
|
||||
return start, end, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ type portMapSorter []portMapEntry
|
|||
func (s portMapSorter) Len() int { return len(s) }
|
||||
func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// sort the port so that the order is:
|
||||
// Less sorts the port so that the order is:
|
||||
// 1. port with larger specified bindings
|
||||
// 2. larger port
|
||||
// 3. port with tcp protocol
|
||||
|
|
@ -58,7 +58,7 @@ func (s portMapSorter) Less(i, j int) bool {
|
|||
func SortPortMap(ports []Port, bindings PortMap) {
|
||||
s := portMapSorter{}
|
||||
for _, p := range ports {
|
||||
if binding, ok := bindings[p]; ok {
|
||||
if binding, ok := bindings[p]; ok && len(binding) > 0 {
|
||||
for _, b := range binding {
|
||||
s = append(s, portMapEntry{port: p, binding: b})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,8 @@ package sockets
|
|||
|
||||
import (
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
// GetProxyEnv allows access to the uppercase and the lowercase forms of
|
||||
|
|
@ -20,32 +17,12 @@ func GetProxyEnv(key string) string {
|
|||
return proxyValue
|
||||
}
|
||||
|
||||
// DialerFromEnvironment takes in a "direct" *net.Dialer and returns a
|
||||
// proxy.Dialer which will route the connections through the proxy using the
|
||||
// given dialer.
|
||||
func DialerFromEnvironment(direct *net.Dialer) (proxy.Dialer, error) {
|
||||
allProxy := GetProxyEnv("all_proxy")
|
||||
if len(allProxy) == 0 {
|
||||
return direct, nil
|
||||
}
|
||||
|
||||
proxyURL, err := url.Parse(allProxy)
|
||||
if err != nil {
|
||||
return direct, err
|
||||
}
|
||||
|
||||
proxyFromURL, err := proxy.FromURL(proxyURL, direct)
|
||||
if err != nil {
|
||||
return direct, err
|
||||
}
|
||||
|
||||
noProxy := GetProxyEnv("no_proxy")
|
||||
if len(noProxy) == 0 {
|
||||
return proxyFromURL, nil
|
||||
}
|
||||
|
||||
perHost := proxy.NewPerHost(proxyFromURL, direct)
|
||||
perHost.AddFromString(noProxy)
|
||||
|
||||
return perHost, nil
|
||||
// DialerFromEnvironment was previously used to configure a net.Dialer to route
|
||||
// connections through a SOCKS proxy.
|
||||
// DEPRECATED: SOCKS proxies are now supported by configuring only
|
||||
// http.Transport.Proxy, and no longer require changing http.Transport.Dial.
|
||||
// Therefore, only sockets.ConfigureTransport() needs to be called, and any
|
||||
// sockets.DialerFromEnvironment() calls can be dropped.
|
||||
func DialerFromEnvironment(direct *net.Dialer) (*net.Dialer, error) {
|
||||
return direct, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,16 +8,18 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// Why 32? See https://github.com/docker/docker/pull/8035.
|
||||
const defaultTimeout = 32 * time.Second
|
||||
const defaultTimeout = 10 * time.Second
|
||||
|
||||
// ErrProtocolNotAvailable is returned when a given transport protocol is not provided by the operating system.
|
||||
var ErrProtocolNotAvailable = errors.New("protocol not available")
|
||||
|
||||
// ConfigureTransport configures the specified Transport according to the
|
||||
// specified proto and addr.
|
||||
// If the proto is unix (using a unix socket to communicate) or npipe the
|
||||
// compression is disabled.
|
||||
// ConfigureTransport configures the specified [http.Transport] according to the specified proto
|
||||
// and addr.
|
||||
//
|
||||
// If the proto is unix (using a unix socket to communicate) or npipe the compression is disabled.
|
||||
// For other protos, compression is enabled. If you want to manually enable/disable compression,
|
||||
// make sure you do it _after_ any subsequent calls to ConfigureTransport is made against the same
|
||||
// [http.Transport].
|
||||
func ConfigureTransport(tr *http.Transport, proto, addr string) error {
|
||||
switch proto {
|
||||
case "unix":
|
||||
|
|
@ -26,13 +28,10 @@ func ConfigureTransport(tr *http.Transport, proto, addr string) error {
|
|||
return configureNpipeTransport(tr, proto, addr)
|
||||
default:
|
||||
tr.Proxy = http.ProxyFromEnvironment
|
||||
dialer, err := DialerFromEnvironment(&net.Dialer{
|
||||
tr.DisableCompression = false
|
||||
tr.DialContext = (&net.Dialer{
|
||||
Timeout: defaultTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tr.Dial = dialer.Dial
|
||||
}).DialContext
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
// +build !windows
|
||||
//go:build !windows
|
||||
|
||||
package sockets
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
|
|
@ -14,12 +15,15 @@ const maxUnixSocketPathSize = len(syscall.RawSockaddrUnix{}.Path)
|
|||
|
||||
func configureUnixTransport(tr *http.Transport, proto, addr string) error {
|
||||
if len(addr) > maxUnixSocketPathSize {
|
||||
return fmt.Errorf("Unix socket path %q is too long", addr)
|
||||
return fmt.Errorf("unix socket path %q is too long", addr)
|
||||
}
|
||||
// No need for compression in local communications.
|
||||
tr.DisableCompression = true
|
||||
tr.Dial = func(_, _ string) (net.Conn, error) {
|
||||
return net.DialTimeout(proto, addr, defaultTimeout)
|
||||
dialer := &net.Dialer{
|
||||
Timeout: defaultTimeout,
|
||||
}
|
||||
tr.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||
return dialer.DialContext(ctx, proto, addr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package sockets
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
|
@ -15,8 +16,8 @@ func configureUnixTransport(tr *http.Transport, proto, addr string) error {
|
|||
func configureNpipeTransport(tr *http.Transport, proto, addr string) error {
|
||||
// No need for compression in local communications.
|
||||
tr.DisableCompression = true
|
||||
tr.Dial = func(_, _ string) (net.Conn, error) {
|
||||
return DialPipe(addr, defaultTimeout)
|
||||
tr.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||
return winio.DialPipeContext(ctx, addr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,51 @@
|
|||
// +build !windows
|
||||
//go:build !windows
|
||||
|
||||
/*
|
||||
Package sockets is a simple unix domain socket wrapper.
|
||||
|
||||
# Usage
|
||||
|
||||
For example:
|
||||
|
||||
import(
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"github.com/docker/go-connections/sockets"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l, err := sockets.NewUnixSocketWithOpts("/path/to/sockets",
|
||||
sockets.WithChown(0,0),sockets.WithChmod(0660))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
echoStr := "hello"
|
||||
|
||||
go func() {
|
||||
for {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn.Write([]byte(echoStr))
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
conn, err := net.Dial("unix", path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
buf := make([]byte, 5)
|
||||
if _, err := conn.Read(buf); err != nil {
|
||||
panic(err)
|
||||
} else if string(buf) != echoStr {
|
||||
panic(fmt.Errorf("msg may lost"))
|
||||
}
|
||||
}
|
||||
*/
|
||||
package sockets
|
||||
|
||||
import (
|
||||
|
|
@ -8,25 +54,73 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
// NewUnixSocket creates a unix socket with the specified path and group.
|
||||
func NewUnixSocket(path string, gid int) (net.Listener, error) {
|
||||
// SockOption sets up socket file's creating option
|
||||
type SockOption func(string) error
|
||||
|
||||
// WithChown modifies the socket file's uid and gid
|
||||
func WithChown(uid, gid int) SockOption {
|
||||
return func(path string) error {
|
||||
if err := os.Chown(path, uid, gid); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithChmod modifies socket file's access mode.
|
||||
func WithChmod(mask os.FileMode) SockOption {
|
||||
return func(path string) error {
|
||||
if err := os.Chmod(path, mask); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewUnixSocketWithOpts creates a unix socket with the specified options.
|
||||
// By default, socket permissions are 0000 (i.e.: no access for anyone); pass
|
||||
// WithChmod() and WithChown() to set the desired ownership and permissions.
|
||||
//
|
||||
// This function temporarily changes the system's "umask" to 0777 to work around
|
||||
// a race condition between creating the socket and setting its permissions. While
|
||||
// this should only be for a short duration, it may affect other processes that
|
||||
// create files/directories during that period.
|
||||
func NewUnixSocketWithOpts(path string, opts ...SockOption) (net.Listener, error) {
|
||||
if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
mask := syscall.Umask(0777)
|
||||
defer syscall.Umask(mask)
|
||||
|
||||
// net.Listen does not allow for permissions to be set. As a result, when
|
||||
// specifying custom permissions ("WithChmod()"), there is a short time
|
||||
// between creating the socket and applying the permissions, during which
|
||||
// the socket permissions are Less restrictive than desired.
|
||||
//
|
||||
// To work around this limitation of net.Listen(), we temporarily set the
|
||||
// umask to 0777, which forces the socket to be created with 000 permissions
|
||||
// (i.e.: no access for anyone). After that, WithChmod() must be used to set
|
||||
// the desired permissions.
|
||||
//
|
||||
// We don't use "defer" here, to reset the umask to its original value as soon
|
||||
// as possible. Ideally we'd be able to detect if WithChmod() was passed as
|
||||
// an option, and skip changing umask if default permissions are used.
|
||||
origUmask := syscall.Umask(0o777)
|
||||
l, err := net.Listen("unix", path)
|
||||
syscall.Umask(origUmask)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.Chown(path, 0, gid); err != nil {
|
||||
l.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := os.Chmod(path, 0660); err != nil {
|
||||
l.Close()
|
||||
return nil, err
|
||||
|
||||
for _, op := range opts {
|
||||
if err := op(path); err != nil {
|
||||
_ = l.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// NewUnixSocket creates a unix socket with the specified path and group.
|
||||
func NewUnixSocket(path string, gid int) (net.Listener, error) {
|
||||
return NewUnixSocketWithOpts(path, WithChown(0, gid), WithChmod(0o660))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
// +build go1.7
|
||||
|
||||
package tlsconfig
|
||||
|
||||
import (
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
// +build !go1.7
|
||||
|
||||
package tlsconfig
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
)
|
||||
|
||||
// SystemCertPool returns an new empty cert pool,
|
||||
// accessing system cert pool is supported in go 1.7
|
||||
func SystemCertPool() (*x509.CertPool, error) {
|
||||
return x509.NewCertPool(), nil
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers.
|
||||
//
|
||||
// As a reminder from https://golang.org/pkg/crypto/tls/#Config:
|
||||
//
|
||||
// A Config structure is used to configure a TLS client or server. After one has been passed to a TLS function it must not be modified.
|
||||
// A Config may be reused; the tls package will also not modify it.
|
||||
package tlsconfig
|
||||
|
|
@ -9,11 +10,9 @@ import (
|
|||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Options represents the information needed to create client and server TLS configurations.
|
||||
|
|
@ -36,7 +35,12 @@ type Options struct {
|
|||
ExclusiveRootPools bool
|
||||
MinVersion uint16
|
||||
// If Passphrase is set, it will be used to decrypt a TLS private key
|
||||
// if the key is encrypted
|
||||
// if the key is encrypted.
|
||||
//
|
||||
// Deprecated: Use of encrypted TLS private keys has been deprecated, and
|
||||
// will be removed in a future release. Golang has deprecated support for
|
||||
// legacy PEM encryption (as specified in RFC 1423), as it is insecure by
|
||||
// design (see https://go-review.googlesource.com/c/go/+/264159).
|
||||
Passphrase string
|
||||
}
|
||||
|
||||
|
|
@ -53,18 +57,9 @@ var acceptedCBCCiphers = []uint16{
|
|||
// known weak algorithms removed.
|
||||
var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...)
|
||||
|
||||
// allTLSVersions lists all the TLS versions and is used by the code that validates
|
||||
// a uint16 value as a TLS version.
|
||||
var allTLSVersions = map[uint16]struct{}{
|
||||
tls.VersionSSL30: {},
|
||||
tls.VersionTLS10: {},
|
||||
tls.VersionTLS11: {},
|
||||
tls.VersionTLS12: {},
|
||||
}
|
||||
|
||||
// ServerDefault returns a secure-enough TLS configuration for the server TLS configuration.
|
||||
func ServerDefault(ops ...func(*tls.Config)) *tls.Config {
|
||||
tlsconfig := &tls.Config{
|
||||
tlsConfig := &tls.Config{
|
||||
// Avoid fallback by default to SSL protocols < TLS1.2
|
||||
MinVersion: tls.VersionTLS12,
|
||||
PreferServerCipherSuites: true,
|
||||
|
|
@ -72,25 +67,25 @@ func ServerDefault(ops ...func(*tls.Config)) *tls.Config {
|
|||
}
|
||||
|
||||
for _, op := range ops {
|
||||
op(tlsconfig)
|
||||
op(tlsConfig)
|
||||
}
|
||||
|
||||
return tlsconfig
|
||||
return tlsConfig
|
||||
}
|
||||
|
||||
// ClientDefault returns a secure-enough TLS configuration for the client TLS configuration.
|
||||
func ClientDefault(ops ...func(*tls.Config)) *tls.Config {
|
||||
tlsconfig := &tls.Config{
|
||||
tlsConfig := &tls.Config{
|
||||
// Prefer TLS1.2 as the client minimum
|
||||
MinVersion: tls.VersionTLS12,
|
||||
CipherSuites: clientCipherSuites,
|
||||
}
|
||||
|
||||
for _, op := range ops {
|
||||
op(tlsconfig)
|
||||
op(tlsConfig)
|
||||
}
|
||||
|
||||
return tlsconfig
|
||||
return tlsConfig
|
||||
}
|
||||
|
||||
// certPool returns an X.509 certificate pool from `caFile`, the certificate file.
|
||||
|
|
@ -108,16 +103,25 @@ func certPool(caFile string, exclusivePool bool) (*x509.CertPool, error) {
|
|||
return nil, fmt.Errorf("failed to read system certificates: %v", err)
|
||||
}
|
||||
}
|
||||
pem, err := ioutil.ReadFile(caFile)
|
||||
pemData, err := os.ReadFile(caFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read CA certificate %q: %v", caFile, err)
|
||||
}
|
||||
if !certPool.AppendCertsFromPEM(pem) {
|
||||
if !certPool.AppendCertsFromPEM(pemData) {
|
||||
return nil, fmt.Errorf("failed to append certificates from PEM file: %q", caFile)
|
||||
}
|
||||
return certPool, nil
|
||||
}
|
||||
|
||||
// allTLSVersions lists all the TLS versions and is used by the code that validates
|
||||
// a uint16 value as a TLS version.
|
||||
var allTLSVersions = map[uint16]struct{}{
|
||||
tls.VersionTLS10: {},
|
||||
tls.VersionTLS11: {},
|
||||
tls.VersionTLS12: {},
|
||||
tls.VersionTLS13: {},
|
||||
}
|
||||
|
||||
// isValidMinVersion checks that the input value is a valid tls minimum version
|
||||
func isValidMinVersion(version uint16) bool {
|
||||
_, ok := allTLSVersions[version]
|
||||
|
|
@ -129,10 +133,10 @@ func isValidMinVersion(version uint16) bool {
|
|||
func adjustMinVersion(options Options, config *tls.Config) error {
|
||||
if options.MinVersion > 0 {
|
||||
if !isValidMinVersion(options.MinVersion) {
|
||||
return fmt.Errorf("Invalid minimum TLS version: %x", options.MinVersion)
|
||||
return fmt.Errorf("invalid minimum TLS version: %x", options.MinVersion)
|
||||
}
|
||||
if options.MinVersion < config.MinVersion {
|
||||
return fmt.Errorf("Requested minimum TLS version is too low. Should be at-least: %x", config.MinVersion)
|
||||
return fmt.Errorf("requested minimum TLS version is too low. Should be at-least: %x", config.MinVersion)
|
||||
}
|
||||
config.MinVersion = options.MinVersion
|
||||
}
|
||||
|
|
@ -141,9 +145,14 @@ func adjustMinVersion(options Options, config *tls.Config) error {
|
|||
}
|
||||
|
||||
// IsErrEncryptedKey returns true if the 'err' is an error of incorrect
|
||||
// password when tryin to decrypt a TLS private key
|
||||
// password when trying to decrypt a TLS private key.
|
||||
//
|
||||
// Deprecated: Use of encrypted TLS private keys has been deprecated, and
|
||||
// will be removed in a future release. Golang has deprecated support for
|
||||
// legacy PEM encryption (as specified in RFC 1423), as it is insecure by
|
||||
// design (see https://go-review.googlesource.com/c/go/+/264159).
|
||||
func IsErrEncryptedKey(err error) bool {
|
||||
return errors.Cause(err) == x509.IncorrectPasswordError
|
||||
return errors.Is(err, x509.IncorrectPasswordError)
|
||||
}
|
||||
|
||||
// getPrivateKey returns the private key in 'keyBytes', in PEM-encoded format.
|
||||
|
|
@ -157,10 +166,10 @@ func getPrivateKey(keyBytes []byte, passphrase string) ([]byte, error) {
|
|||
}
|
||||
|
||||
var err error
|
||||
if x509.IsEncryptedPEMBlock(pemBlock) {
|
||||
keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(passphrase))
|
||||
if x509.IsEncryptedPEMBlock(pemBlock) { //nolint:staticcheck // Ignore SA1019 (IsEncryptedPEMBlock is deprecated)
|
||||
keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(passphrase)) //nolint:staticcheck // Ignore SA1019 (DecryptPEMBlock is deprecated)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "private key is encrypted, but could not decrypt it")
|
||||
return nil, fmt.Errorf("private key is encrypted, but could not decrypt it: %w", err)
|
||||
}
|
||||
keyBytes = pem.EncodeToMemory(&pem.Block{Type: pemBlock.Type, Bytes: keyBytes})
|
||||
}
|
||||
|
|
@ -176,26 +185,24 @@ func getCert(options Options) ([]tls.Certificate, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
errMessage := "Could not load X509 key pair"
|
||||
|
||||
cert, err := ioutil.ReadFile(options.CertFile)
|
||||
cert, err := os.ReadFile(options.CertFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMessage)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prKeyBytes, err := ioutil.ReadFile(options.KeyFile)
|
||||
prKeyBytes, err := os.ReadFile(options.KeyFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMessage)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prKeyBytes, err = getPrivateKey(prKeyBytes, options.Passphrase)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMessage)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsCert, err := tls.X509KeyPair(cert, prKeyBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, errMessage)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []tls.Certificate{tlsCert}, nil
|
||||
|
|
@ -215,7 +222,7 @@ func Client(options Options) (*tls.Config, error) {
|
|||
|
||||
tlsCerts, err := getCert(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("could not load X509 key pair: %w", err)
|
||||
}
|
||||
tlsConfig.Certificates = tlsCerts
|
||||
|
||||
|
|
@ -233,9 +240,9 @@ func Server(options Options) (*tls.Config, error) {
|
|||
tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("Could not load X509 key pair (cert: %q, key: %q): %v", options.CertFile, options.KeyFile, err)
|
||||
return nil, fmt.Errorf("could not load X509 key pair (cert: %q, key: %q): %v", options.CertFile, options.KeyFile, err)
|
||||
}
|
||||
return nil, fmt.Errorf("Error reading X509 key pair (cert: %q, key: %q): %v. Make sure the key is not encrypted.", options.CertFile, options.KeyFile, err)
|
||||
return nil, fmt.Errorf("error reading X509 key pair - make sure the key is not encrypted (cert: %q, key: %q): %v", options.CertFile, options.KeyFile, err)
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{tlsCert}
|
||||
if options.ClientAuth >= tls.VerifyClientCertIfGiven && options.CAFile != "" {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
// +build go1.5
|
||||
|
||||
// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers.
|
||||
//
|
||||
package tlsconfig
|
||||
|
||||
import (
|
||||
|
|
|
|||
15
vendor/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go
generated
vendored
15
vendor/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go
generated
vendored
|
|
@ -1,15 +0,0 @@
|
|||
// +build !go1.5
|
||||
|
||||
// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers.
|
||||
//
|
||||
package tlsconfig
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
)
|
||||
|
||||
// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set)
|
||||
var clientCipherSuites = []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
}
|
||||
|
|
@ -16,6 +16,14 @@ This package provides various compression algorithms.
|
|||
|
||||
# changelog
|
||||
|
||||
* Oct 22nd, 2023 - [v1.17.2](https://github.com/klauspost/compress/releases/tag/v1.17.2)
|
||||
* zstd: Fix rare *CORRUPTION* output in "best" mode. See https://github.com/klauspost/compress/pull/876
|
||||
|
||||
* Oct 14th, 2023 - [v1.17.1](https://github.com/klauspost/compress/releases/tag/v1.17.1)
|
||||
* s2: Fix S2 "best" dictionary wrong encoding by @klauspost in https://github.com/klauspost/compress/pull/871
|
||||
* flate: Reduce allocations in decompressor and minor code improvements by @fakefloordiv in https://github.com/klauspost/compress/pull/869
|
||||
* s2: Fix EstimateBlockSize on 6&7 length input by @klauspost in https://github.com/klauspost/compress/pull/867
|
||||
|
||||
* Sept 19th, 2023 - [v1.17.0](https://github.com/klauspost/compress/releases/tag/v1.17.0)
|
||||
* Add experimental dictionary builder https://github.com/klauspost/compress/pull/853
|
||||
* Add xerial snappy read/writer https://github.com/klauspost/compress/pull/838
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ func (s *Scratch) writeCount() error {
|
|||
previous0 bool
|
||||
charnum uint16
|
||||
|
||||
maxHeaderSize = ((int(s.symbolLen) * int(tableLog)) >> 3) + 3
|
||||
maxHeaderSize = ((int(s.symbolLen)*int(tableLog) + 4 + 2) >> 3) + 3
|
||||
|
||||
// Write Table Size
|
||||
bitStream = uint32(tableLog - minTablelog)
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright 2018 Klaus Post. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
|
||||
|
||||
package huff0
|
||||
|
||||
// byteReader provides a byte reader that reads
|
||||
// little endian values from a byte stream.
|
||||
// The input stream is manually advanced.
|
||||
// The reader performs no bounds checks.
|
||||
type byteReader struct {
|
||||
b []byte
|
||||
off int
|
||||
}
|
||||
|
||||
// init will initialize the reader and set the input.
|
||||
func (b *byteReader) init(in []byte) {
|
||||
b.b = in
|
||||
b.off = 0
|
||||
}
|
||||
|
||||
// Int32 returns a little endian int32 starting at current offset.
|
||||
func (b byteReader) Int32() int32 {
|
||||
v3 := int32(b.b[b.off+3])
|
||||
v2 := int32(b.b[b.off+2])
|
||||
v1 := int32(b.b[b.off+1])
|
||||
v0 := int32(b.b[b.off])
|
||||
return (v3 << 24) | (v2 << 16) | (v1 << 8) | v0
|
||||
}
|
||||
|
||||
// Uint32 returns a little endian uint32 starting at current offset.
|
||||
func (b byteReader) Uint32() uint32 {
|
||||
v3 := uint32(b.b[b.off+3])
|
||||
v2 := uint32(b.b[b.off+2])
|
||||
v1 := uint32(b.b[b.off+1])
|
||||
v0 := uint32(b.b[b.off])
|
||||
return (v3 << 24) | (v2 << 16) | (v1 << 8) | v0
|
||||
}
|
||||
|
||||
// remain will return the number of bytes remaining.
|
||||
func (b byteReader) remain() int {
|
||||
return len(b.b) - b.off
|
||||
}
|
||||
|
|
@ -350,6 +350,7 @@ func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
|
|||
// Does not update s.clearCount.
|
||||
func (s *Scratch) countSimple(in []byte) (max int, reuse bool) {
|
||||
reuse = true
|
||||
_ = s.count // Assert that s != nil to speed up the following loop.
|
||||
for _, v := range in {
|
||||
s.count[v]++
|
||||
}
|
||||
|
|
@ -415,7 +416,7 @@ func (s *Scratch) validateTable(c cTable) bool {
|
|||
|
||||
// minTableLog provides the minimum logSize to safely represent a distribution.
|
||||
func (s *Scratch) minTableLog() uint8 {
|
||||
minBitsSrc := highBit32(uint32(s.br.remain())) + 1
|
||||
minBitsSrc := highBit32(uint32(s.srcLen)) + 1
|
||||
minBitsSymbols := highBit32(uint32(s.symbolLen-1)) + 2
|
||||
if minBitsSrc < minBitsSymbols {
|
||||
return uint8(minBitsSrc)
|
||||
|
|
@ -427,7 +428,7 @@ func (s *Scratch) minTableLog() uint8 {
|
|||
func (s *Scratch) optimalTableLog() {
|
||||
tableLog := s.TableLog
|
||||
minBits := s.minTableLog()
|
||||
maxBitsSrc := uint8(highBit32(uint32(s.br.remain()-1))) - 1
|
||||
maxBitsSrc := uint8(highBit32(uint32(s.srcLen-1))) - 1
|
||||
if maxBitsSrc < tableLog {
|
||||
// Accuracy can be reduced
|
||||
tableLog = maxBitsSrc
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ type Scratch struct {
|
|||
// Decoders will return ErrMaxDecodedSizeExceeded is this limit is exceeded.
|
||||
MaxDecodedSize int
|
||||
|
||||
br byteReader
|
||||
srcLen int
|
||||
|
||||
// MaxSymbolValue will override the maximum symbol value of the next block.
|
||||
MaxSymbolValue uint8
|
||||
|
|
@ -170,7 +170,7 @@ func (s *Scratch) prepare(in []byte) (*Scratch, error) {
|
|||
if s.fse == nil {
|
||||
s.fse = &fse.Scratch{}
|
||||
}
|
||||
s.br.init(in)
|
||||
s.srcLen = len(in)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ nyc-taxi-data-10M.csv gzkp 1 3325605752 922273214 13929 227.68
|
|||
|
||||
## Decompressor
|
||||
|
||||
Staus: STABLE - there may still be subtle bugs, but a wide variety of content has been tested.
|
||||
Status: STABLE - there may still be subtle bugs, but a wide variety of content has been tested.
|
||||
|
||||
This library is being continuously [fuzz-tested](https://github.com/klauspost/compress-fuzz),
|
||||
kindly supplied by [fuzzit.dev](https://fuzzit.dev/).
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func (m *match) estBits(bitsPerByte int32) {
|
|||
if m.rep < 0 {
|
||||
ofc = ofCode(uint32(m.s-m.offset) + 3)
|
||||
} else {
|
||||
ofc = ofCode(uint32(m.rep))
|
||||
ofc = ofCode(uint32(m.rep) & 3)
|
||||
}
|
||||
// Cost, excluding
|
||||
ofTT, mlTT := fsePredefEnc[tableOffsets].ct.symbolTT[ofc], fsePredefEnc[tableMatchLengths].ct.symbolTT[mlc]
|
||||
|
|
@ -227,7 +227,7 @@ encodeLoop:
|
|||
}
|
||||
}
|
||||
l := 4 + e.matchlen(s+4, offset+4, src)
|
||||
if rep < 0 {
|
||||
if true {
|
||||
// Extend candidate match backwards as far as possible.
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
|
|
@ -282,6 +282,7 @@ encodeLoop:
|
|||
// Load next and check...
|
||||
e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: candidateL.offset}
|
||||
e.table[nextHashS] = prevEntry{offset: s + e.cur, prev: candidateS.offset}
|
||||
index0 := s + 1
|
||||
|
||||
// Look far ahead, unless we have a really long match already...
|
||||
if best.length < goodEnough {
|
||||
|
|
@ -357,19 +358,16 @@ encodeLoop:
|
|||
blk.sequences = append(blk.sequences, seq)
|
||||
|
||||
// Index old s + 1 -> s - 1
|
||||
index0 := s + 1
|
||||
s = best.s + best.length
|
||||
|
||||
nextEmit = s
|
||||
if s >= sLimit {
|
||||
if debugEncoder {
|
||||
println("repeat ended", s, best.length)
|
||||
}
|
||||
break encodeLoop
|
||||
}
|
||||
|
||||
// Index skipped...
|
||||
end := s
|
||||
if s > sLimit+4 {
|
||||
end = sLimit + 4
|
||||
}
|
||||
off := index0 + e.cur
|
||||
for index0 < s {
|
||||
for index0 < end {
|
||||
cv0 := load6432(src, index0)
|
||||
h0 := hashLen(cv0, bestLongTableBits, bestLongLen)
|
||||
h1 := hashLen(cv0, bestShortTableBits, bestShortLen)
|
||||
|
|
@ -378,6 +376,7 @@ encodeLoop:
|
|||
off++
|
||||
index0++
|
||||
}
|
||||
|
||||
switch best.rep {
|
||||
case 2, 4 | 1:
|
||||
offset1, offset2 = offset2, offset1
|
||||
|
|
@ -386,12 +385,17 @@ encodeLoop:
|
|||
case 4 | 3:
|
||||
offset1, offset2, offset3 = offset1-1, offset1, offset2
|
||||
}
|
||||
if s >= sLimit {
|
||||
if debugEncoder {
|
||||
println("repeat ended", s, best.length)
|
||||
}
|
||||
break encodeLoop
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// A 4-byte match has been found. Update recent offsets.
|
||||
// We'll later see if more than 4 bytes.
|
||||
index0 := s + 1
|
||||
s = best.s
|
||||
t := best.offset
|
||||
offset1, offset2, offset3 = s-t, offset1, offset2
|
||||
|
|
@ -419,19 +423,25 @@ encodeLoop:
|
|||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
nextEmit = s
|
||||
if s >= sLimit {
|
||||
break encodeLoop
|
||||
|
||||
// Index old s + 1 -> s - 1 or sLimit
|
||||
end := s
|
||||
if s > sLimit-4 {
|
||||
end = sLimit - 4
|
||||
}
|
||||
|
||||
// Index old s + 1 -> s - 1
|
||||
for index0 < s {
|
||||
off := index0 + e.cur
|
||||
for index0 < end {
|
||||
cv0 := load6432(src, index0)
|
||||
h0 := hashLen(cv0, bestLongTableBits, bestLongLen)
|
||||
h1 := hashLen(cv0, bestShortTableBits, bestShortLen)
|
||||
off := index0 + e.cur
|
||||
e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
|
||||
e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset}
|
||||
index0++
|
||||
off++
|
||||
}
|
||||
if s >= sLimit {
|
||||
break encodeLoop
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ encodeLoop:
|
|||
var t int32
|
||||
// We allow the encoder to optionally turn off repeat offsets across blocks
|
||||
canRepeat := len(blk.sequences) > 2
|
||||
var matched int32
|
||||
var matched, index0 int32
|
||||
|
||||
for {
|
||||
if debugAsserts && canRepeat && offset1 == 0 {
|
||||
|
|
@ -162,6 +162,7 @@ encodeLoop:
|
|||
off := s + e.cur
|
||||
e.longTable[nextHashL] = prevEntry{offset: off, prev: candidateL.offset}
|
||||
e.table[nextHashS] = tableEntry{offset: off, val: uint32(cv)}
|
||||
index0 = s + 1
|
||||
|
||||
if canRepeat {
|
||||
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
||||
|
|
@ -258,7 +259,6 @@ encodeLoop:
|
|||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
|
||||
index0 := s + repOff2
|
||||
s += lenght + repOff2
|
||||
nextEmit = s
|
||||
if s >= sLimit {
|
||||
|
|
@ -498,15 +498,15 @@ encodeLoop:
|
|||
}
|
||||
|
||||
// Index match start+1 (long) -> s - 1
|
||||
index0 := s - l + 1
|
||||
off := index0 + e.cur
|
||||
for index0 < s-1 {
|
||||
cv0 := load6432(src, index0)
|
||||
cv1 := cv0 >> 8
|
||||
h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
|
||||
off := index0 + e.cur
|
||||
e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
|
||||
e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)}
|
||||
index0 += 2
|
||||
off += 2
|
||||
}
|
||||
|
||||
cv = load6432(src, s)
|
||||
|
|
@ -672,7 +672,7 @@ encodeLoop:
|
|||
var t int32
|
||||
// We allow the encoder to optionally turn off repeat offsets across blocks
|
||||
canRepeat := len(blk.sequences) > 2
|
||||
var matched int32
|
||||
var matched, index0 int32
|
||||
|
||||
for {
|
||||
if debugAsserts && canRepeat && offset1 == 0 {
|
||||
|
|
@ -691,6 +691,7 @@ encodeLoop:
|
|||
e.markLongShardDirty(nextHashL)
|
||||
e.table[nextHashS] = tableEntry{offset: off, val: uint32(cv)}
|
||||
e.markShortShardDirty(nextHashS)
|
||||
index0 = s + 1
|
||||
|
||||
if canRepeat {
|
||||
if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
|
||||
|
|
@ -726,7 +727,6 @@ encodeLoop:
|
|||
blk.sequences = append(blk.sequences, seq)
|
||||
|
||||
// Index match start+1 (long) -> s - 1
|
||||
index0 := s + repOff
|
||||
s += lenght + repOff
|
||||
|
||||
nextEmit = s
|
||||
|
|
@ -790,7 +790,6 @@ encodeLoop:
|
|||
}
|
||||
blk.sequences = append(blk.sequences, seq)
|
||||
|
||||
index0 := s + repOff2
|
||||
s += lenght + repOff2
|
||||
nextEmit = s
|
||||
if s >= sLimit {
|
||||
|
|
@ -1024,18 +1023,18 @@ encodeLoop:
|
|||
}
|
||||
|
||||
// Index match start+1 (long) -> s - 1
|
||||
index0 := s - l + 1
|
||||
off := index0 + e.cur
|
||||
for index0 < s-1 {
|
||||
cv0 := load6432(src, index0)
|
||||
cv1 := cv0 >> 8
|
||||
h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
|
||||
off := index0 + e.cur
|
||||
e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
|
||||
e.markLongShardDirty(h0)
|
||||
h1 := hashLen(cv1, betterShortTableBits, betterShortLen)
|
||||
e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)}
|
||||
e.markShortShardDirty(h1)
|
||||
index0 += 2
|
||||
off += 2
|
||||
}
|
||||
|
||||
cv = load6432(src, s)
|
||||
|
|
|
|||
|
|
@ -1,66 +1,284 @@
|
|||
# This file lists all individuals having contributed content to the repository.
|
||||
# For how it is generated, see `scripts/generate-authors.sh`.
|
||||
# For how it is generated, see hack/dockerfiles/authors.Dockerfile.
|
||||
|
||||
a-palchikov <deemok@gmail.com>
|
||||
Aaron L. Xu <likexu@harmonycloud.cn>
|
||||
Aaron Lehmann <aaron.lehmann@docker.com>
|
||||
Aaron Lehmann <alehmann@netflix.com>
|
||||
Abdur Rehman <abdur_rehman@mentor.com>
|
||||
Addam Hardy <addam.hardy@gmail.com>
|
||||
Adrian Plata <adrian.plata@docker.com>
|
||||
Aidan Hobson Sayers <aidanhs@cantab.net>
|
||||
Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
|
||||
Alan Fregtman <941331+darkvertex@users.noreply.github.com>
|
||||
Alex Couture-Beil <alex@earthly.dev>
|
||||
Alex Mayer <amayer5125@gmail.com>
|
||||
Alex Suraci <suraci.alex@gmail.com>
|
||||
Alexander Morozov <lk4d4@docker.com>
|
||||
Alexis Murzeau <amubtdx@gmail.com>
|
||||
Alice Frosi <afrosi@de.ibm.com>
|
||||
Allen Sun <allen.sun@daocloud.io>
|
||||
Amen Belayneh <amenbelayneh@gmail.com>
|
||||
Anca Iordache <anca.iordache@docker.com>
|
||||
Anda Xu <anda.xu@docker.com>
|
||||
Anders F Björklund <anders.f.bjorklund@gmail.com>
|
||||
Andrea Bolognani <abologna@redhat.com>
|
||||
Andrea Luzzardi <aluzzardi@gmail.com>
|
||||
Andrew Chang <chang331006@gmail.com>
|
||||
Andrey Smirnov <smirnov.andrey@gmail.com>
|
||||
Andy Alt <andy5995@users.noreply.github.com>
|
||||
Andy Caldwell <andrew.caldwell@metaswitch.com>
|
||||
Ankush Agarwal <ankushagarwal11@gmail.com>
|
||||
Anthony Sottile <asottile@umich.edu>
|
||||
Anurag Goel <anurag@render.com>
|
||||
Anusha Ragunathan <anusha@docker.com>
|
||||
Arnaud Bailly <arnaud.oqube@gmail.com>
|
||||
Avi Deitcher <avi@deitcher.net>
|
||||
Bastiaan Bakker <bbakker@xebia.com>
|
||||
Ben Longo <benlongo9807@gmail.com>
|
||||
Bertrand Paquet <bertrand.paquet@gmail.com>
|
||||
Bin Liu <liubin0329@gmail.com>
|
||||
Brandon Mitchell <git@bmitch.net>
|
||||
Brian Goff <cpuguy83@gmail.com>
|
||||
Ce Gao <ce.gao@outlook.com>
|
||||
Chaerim Yeo <yeochaerim@gmail.com>
|
||||
Changwei Ge <gechangwei@bytedance.com>
|
||||
Chanhun Jeong <chanhun.jeong@navercorp.com>
|
||||
ChaosGramer <ChaosGramer@users.noreply.github.com>
|
||||
Charles Chan <charleswhchan@users.noreply.github.com>
|
||||
Charles Korn <me@charleskorn.com>
|
||||
Charles Law <claw@conduce.com>
|
||||
Chenbin <chen.bin11@zte.com.cn>
|
||||
Chris Goller <goller@gmail.com>
|
||||
Chris McKinnel <chrismckinnel@gmail.com>
|
||||
Christian Höltje <docwhat@gerf.org>
|
||||
Christian Weichel <chris@gitpod.io>
|
||||
Ciro S. Costa <cscosta@pivotal.io>
|
||||
Claudiu Belu <cbelu@cloudbasesolutions.com>
|
||||
Colin Chartier <colin.n.chartier@gmail.com>
|
||||
Corey Larson <corey@earthly.dev>
|
||||
Cory Bennett <cbennett@netflix.com>
|
||||
Cory Snider <csnider@mirantis.com>
|
||||
coryb <cbennett@netflix.com>
|
||||
CrazyMax <github@crazymax.dev>
|
||||
Csaba Apagyi <csaba.apagyi@gmail.com>
|
||||
Dan Duvall <dduvall@wikimedia.org>
|
||||
Daniel Cassidy <mail@danielcassidy.me.uk>
|
||||
Daniel Nephin <dnephin@gmail.com>
|
||||
Darren Shepherd <darren@rancher.com>
|
||||
Dave Chen <dave.chen@arm.com>
|
||||
Dave Henderson <dhenderson@gmail.com>
|
||||
Dave Tucker <dt@docker.com>
|
||||
David Calavera <david.calavera@gmail.com>
|
||||
David Dooling <dooling@gmail.com>
|
||||
David Gageot <david.gageot@docker.com>
|
||||
David Karlsson <david.karlsson@docker.com>
|
||||
Davis Schirmer <djds@bghost.xyz>
|
||||
Dennis Chen <dennis.chen@arm.com>
|
||||
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
||||
Derek McGowan <derek@mcgstyle.net>
|
||||
Dharmit Shah <shahdharmit@gmail.com>
|
||||
Ding Fei <dingfei@stars.org.cn>
|
||||
dito <itodaisuke00@gmail.com>
|
||||
Doug Davis <dug@us.ibm.com>
|
||||
Edgar Lee <edgarl@netflix.com>
|
||||
Edgar Lee <edgarhinshunlee@gmail.com>
|
||||
Eli Uriegas <eli.uriegas@docker.com>
|
||||
Elias Faxö <elias.faxo@tre.se>
|
||||
Eng Zer Jun <engzerjun@gmail.com>
|
||||
Eric Engestrom <eric@engestrom.ch>
|
||||
Erik Sipsma <erik@sipsma.dev>
|
||||
eyherabh <hugogabriel.eyherabide@gmail.com>
|
||||
f0 <f0@users.noreply.github.com>
|
||||
Fernando Miguel <github@FernandoMiguel.net>
|
||||
Fiona Klute <fiona.klute@gmx.de>
|
||||
Foysal Iqbal <foysal.iqbal.fb@gmail.com>
|
||||
Fred Cox <mcfedr@gmail.com>
|
||||
Frieder Bluemle <frieder.bluemle@gmail.com>
|
||||
Gabriel <samfiragabriel@gmail.com>
|
||||
Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
|
||||
Gaetan de Villele <gdevillele@gmail.com>
|
||||
Gahl Saraf <saraf.gahl@gmail.com>
|
||||
genglu.gl <luzigeng32@163.com>
|
||||
George <george@betterde.com>
|
||||
ggjulio <juligonz@student.42.fr>
|
||||
Govind Rai <raigovind93@gmail.com>
|
||||
Grant Reaber <grant.reaber@gmail.com>
|
||||
Guilhem C <guilhem.charles@gmail.com>
|
||||
Hans van den Bogert <hansbogert@gmail.com>
|
||||
Hao Hu <hao.hu.fr@gmail.com>
|
||||
Hector S <hfsam88@gmail.com>
|
||||
Helen Xie <chenjg@harmonycloud.cn>
|
||||
Himanshu Pandey <hpandey@pivotal.io>
|
||||
Hiromu Nakamura <abctail30@gmail.com>
|
||||
HowJMay <vulxj0j8j8@gmail.com>
|
||||
Hugo Santos <hugo@namespacelabs.com>
|
||||
Ian Campbell <ijc@docker.com>
|
||||
Ilya Dmitrichenko <errordeveloper@gmail.com>
|
||||
Iskander (Alex) Sharipov <quasilyte@gmail.com>
|
||||
Jacob Gillespie <jacobwgillespie@gmail.com>
|
||||
Jacob MacElroy <jacob@okteto.com>
|
||||
Jean-Pierre Huynh <jean-pierre.huynh@ounet.fr>
|
||||
Jeffrey Huang <jeffreyhuang23@gmail.com>
|
||||
Jesse Rittner <rittneje@gmail.com>
|
||||
Jessica Frazelle <acidburn@microsoft.com>
|
||||
jgeiger <jgeiger@gmail.com>
|
||||
Jitender Kumar <jitender.kumar@intel.com>
|
||||
jlecordier <jeanlecordier@hotmail.fr>
|
||||
joey <zchengjoey@gmail.com>
|
||||
John Howard <jhoward@microsoft.com>
|
||||
John Maguire <jmaguire@duosecurity.com>
|
||||
John Mulhausen <john@docker.com>
|
||||
John Tims <john.k.tims@gmail.com>
|
||||
Jon Zeolla <zeolla@gmail.com>
|
||||
Jonathan Azoff <azoff@users.noreply.github.com>
|
||||
Jonathan Giannuzzi <jonathan@giannuzzi.me>
|
||||
Jonathan Stoppani <jonathan.stoppani@divio.com>
|
||||
Jonny Stoten <jonny.stoten@docker.com>
|
||||
JordanGoasdoue <jordan.goasdoue@dailymotion.com>
|
||||
jroenf <jeroenfranse@gmail.com>
|
||||
Julian Goede <julian.goede@pm.me>
|
||||
Justas Brazauskas <brazauskasjustas@gmail.com>
|
||||
Justin Chadwell <me@jedevc.com>
|
||||
Justin Cormack <justin.cormack@docker.com>
|
||||
Justin Garrison <justin@linux.com>
|
||||
Jörg Franke <359489+NewJorg@users.noreply.github.com>
|
||||
Kang, Matthew <impulsecss@gmail.com>
|
||||
Kees Cook <keescook@chromium.org>
|
||||
Kevin Burke <kev@inburke.com>
|
||||
kevinmeredith <kevin.m.meredith@gmail.com>
|
||||
Kir Kolyshkin <kolyshkin@gmail.com>
|
||||
Kohei Tokunaga <ktokunaga.mail@gmail.com>
|
||||
Koichi Shiraishi <zchee.io@gmail.com>
|
||||
Kris-Mikael Krister <krismikael@protonmail.com>
|
||||
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
|
||||
Kyle <Kylemit@gmail.com>
|
||||
l00397676 <lujingxiao@huawei.com>
|
||||
Lajos Papp <lalyos@yahoo.com>
|
||||
lalyos <lalyos@yahoo.com>
|
||||
Levi Harrison <levisamuelharrison@gmail.com>
|
||||
liwenqi <vikilwq@zju.edu.cn>
|
||||
lixiaobing10051267 <li.xiaobing1@zte.com.cn>
|
||||
lomot <lomot@qq.com>
|
||||
Lu Jingxiao <lujingxiao@huawei.com>
|
||||
Luca Visentin <luck.visentin@gmail.com>
|
||||
Maciej Kalisz <mdkalish@users.noreply.github.com>
|
||||
Madhav Puri <madhav.puri@gmail.com>
|
||||
Manu Gupta <manugupt1@gmail.com>
|
||||
Marcus Comstedt <marcus@mc.pp.se>
|
||||
Mark Gordon <msg555@gmail.com>
|
||||
Marko Kohtala <marko.kohtala@gmail.com>
|
||||
Mary Anthony <mary@docker.com>
|
||||
masibw <masi19bw@gmail.com>
|
||||
Matias Insaurralde <matias@insaurral.de>
|
||||
Matt Kang <impulsecss@gmail.com>
|
||||
Matt Rickard <mrick@google.com>
|
||||
Maxime Lagresle <maxime@angel.co>
|
||||
Michael Crosby <crosbymichael@gmail.com>
|
||||
Michael Friis <friism@gmail.com>
|
||||
Michael Irwin <mikesir87@gmail.com>
|
||||
Miguel Ángel Jimeno <miguelangel4b@gmail.com>
|
||||
Mihai Borobocea <MihaiBorob@gmail.com>
|
||||
Mike Brown <brownwm@us.ibm.com>
|
||||
mikelinjie <294893458@qq.com>
|
||||
Mikhail Vasin <vasin@cloud-tv.ru>
|
||||
Misty Stanley-Jones <misty@docker.com>
|
||||
Miyachi Katsuya <miyachi_katsuya@r.recruit.co.jp>
|
||||
Morgan Bauer <mbauer@us.ibm.com>
|
||||
Morlay <morlay.null@gmail.com>
|
||||
msg <msg@clinc.com>
|
||||
Nao YONASHIRO <yonashiro@r.recruit.co.jp>
|
||||
Natasha Jarus <linuxmercedes@gmail.com>
|
||||
Nathan Sullivan <nathan@nightsys.net>
|
||||
Nick Miyake <nmiyake@users.noreply.github.com>
|
||||
Nick Santos <nick.santos@docker.com>
|
||||
Nikhil Pandeti <nikhil.pandeti@utexas.edu>
|
||||
Noel Georgi <18496730+frezbo@users.noreply.github.com>
|
||||
Oliver Bristow <oliver.bristow@project-tracr.com>
|
||||
Omer Duchovne <79370724+od-cyera@users.noreply.github.com>
|
||||
Omer Mizrahi <ommizrah@microsoft.com>
|
||||
Ondrej Fabry <ofabry@cisco.com>
|
||||
Otto Kekäläinen <otto@seravo.fi>
|
||||
Pablo Chico de Guzman <pchico83@gmail.com>
|
||||
Patrick Hemmer <patrick.hemmer@gmail.com>
|
||||
Patrick Lang <plang@microsoft.com>
|
||||
Patrick Van Stee <patrick@vanstee.me>
|
||||
Paul "TBBle" Hampson <Paul.Hampson@Pobox.com>
|
||||
Paweł Gronowski <pawel.gronowski@docker.com>
|
||||
Peter Dave Hello <hsu@peterdavehello.org>
|
||||
Petr Fedchenkov <giggsoff@gmail.com>
|
||||
Phil Estes <estesp@gmail.com>
|
||||
Pierre Fenoll <pierrefenoll@gmail.com>
|
||||
pieterdd <pieterdd@users.noreply.github.com>
|
||||
Pranav Pandit <pranavp@microsoft.com>
|
||||
Pratik Raj <rajpratik71@gmail.com>
|
||||
Prayag Verma <prayag.verma@gmail.com>
|
||||
Qiang Huang <h.huangqiang@huawei.com>
|
||||
Remy Suen <remy.suen@gmail.com>
|
||||
Ri Xu <xuri.me@gmail.com>
|
||||
Rob Taylor <rob@shape.build>
|
||||
Robert Estelle <robertestelle@gmail.com>
|
||||
Rubens Figueiredo <r.figueiredo.52@gmail.com>
|
||||
Sam Whited <sam@samwhited.com>
|
||||
Sascha Schwarze <schwarzs@de.ibm.com>
|
||||
Sean P. Kane <spkane00@gmail.com>
|
||||
Sebastiaan van Stijn <github@gone.nl>
|
||||
Seiya Miyata <odradek38@gmail.com>
|
||||
Serhat Gülçiçek <serhat25@gmail.com>
|
||||
Sertac Ozercan <sozercan@gmail.com>
|
||||
Shev Yan <yandong_8212@163.com>
|
||||
Shijiang Wei <mountkin@gmail.com>
|
||||
Shingo Omura <everpeace@gmail.com>
|
||||
Shiwei Zhang <shizh@microsoft.com>
|
||||
Siebe Schaap <siebe@digibites.nl>
|
||||
Silvin Lubecki <31478878+silvin-lubecki@users.noreply.github.com>
|
||||
Simon Ferquel <simon.ferquel@docker.com>
|
||||
Slava Semushin <semushin@redhat.com>
|
||||
Solomon Hykes <sh.github.6811@hykes.org>
|
||||
squeegels <1674195+squeegels@users.noreply.github.com>
|
||||
Stefan Scherer <stefan.scherer@docker.com>
|
||||
Stefan Weil <sw@weilnetz.de>
|
||||
StefanSchoof <Stefan.Schoof@direkt-gruppe.de>
|
||||
Stepan Blyshchak <stepanblischak@gmail.com>
|
||||
Steve Lohr <schdief.law@gmail.com>
|
||||
sunchunming <sunchunming1@jd.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au>
|
||||
Takuya Noguchi <takninnovationresearch@gmail.com>
|
||||
Thomas Leonard <thomas.leonard@docker.com>
|
||||
Thomas Riccardi <riccardi@systran.fr>
|
||||
Thomas Shaw <tomwillfixit@users.noreply.github.com>
|
||||
Tianon Gravi <admwiggin@gmail.com>
|
||||
Tibor Vass <tibor@docker.com>
|
||||
Tiffany Jernigan <tiffany.f.j@gmail.com>
|
||||
Tim Waugh <twaugh@redhat.com>
|
||||
Tim Wraight <tim.wraight@tangentlabs.co.uk>
|
||||
Tino Rusch <tino.rusch@gmail.com>
|
||||
Tobias Klauser <tklauser@distanz.ch>
|
||||
Tomas Tomecek <ttomecek@redhat.com>
|
||||
Tomasz Kopczynski <tomek@kopczynski.net.pl>
|
||||
Tomohiro Kusumoto <zabio1192@gmail.com>
|
||||
Troels Liebe Bentsen <tlb@nversion.dk>
|
||||
Tõnis Tiigi <tonistiigi@gmail.com>
|
||||
Valentin Lorentz <progval+git@progval.net>
|
||||
Vasek - Tom C <tom.chauveau@epitech.eu>
|
||||
Victor Vieux <victorvieux@gmail.com>
|
||||
Victoria Bialas <victoria.bialas@docker.com>
|
||||
Vincent Demeester <vincent.demeester@docker.com>
|
||||
Vlad A. Ionescu <vladaionescu@users.noreply.github.com>
|
||||
Vladislav Ivanov <vlad@ivanov.email>
|
||||
Wang Yumu <37442693@qq.com>
|
||||
Wei Fu <fuweid89@gmail.com>
|
||||
Wei Zhang <kweizh@gmail.com>
|
||||
wingkwong <wingkwong.code@gmail.com>
|
||||
Xiaofan Zhang <xiaofan.zhang@clinc.com>
|
||||
Ximo Guanter <ximo.guanter@gmail.com>
|
||||
Yamazaki Masashi <masi19bw@gmail.com>
|
||||
Yan Song <imeoer@linux.alibaba.com>
|
||||
Yong Tang <yong.tang.github@outlook.com>
|
||||
Yuichiro Kaneko <spiketeika@gmail.com>
|
||||
Yurii Rashkovskii <yrashk@gmail.com>
|
||||
Zach Badgett <zach.badgett@gmail.com>
|
||||
zhangwenlong <zhangwenlong8911@163.com>
|
||||
Ziv Tsarfati <digger18@gmail.com>
|
||||
岁丰 <genglu.gl@antfin.com>
|
||||
沈陵 <shenling.yyb@alibaba-inc.com>
|
||||
郑泽宇 <perhapszzy@sina.com>
|
||||
|
|
|
|||
65
vendor/github.com/moby/buildkit/frontend/dockerfile/dockerignore/dockerignore.go
generated
vendored
65
vendor/github.com/moby/buildkit/frontend/dockerfile/dockerignore/dockerignore.go
generated
vendored
|
|
@ -1,65 +0,0 @@
|
|||
package dockerignore
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ReadAll reads a .dockerignore file and returns the list of file patterns
|
||||
// to ignore. Note this will trim whitespace from each line as well
|
||||
// as use GO's "clean" func to get the shortest/cleanest path for each.
|
||||
func ReadAll(reader io.Reader) ([]string, error) {
|
||||
if reader == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(reader)
|
||||
var excludes []string
|
||||
currentLine := 0
|
||||
|
||||
utf8bom := []byte{0xEF, 0xBB, 0xBF}
|
||||
for scanner.Scan() {
|
||||
scannedBytes := scanner.Bytes()
|
||||
// We trim UTF8 BOM
|
||||
if currentLine == 0 {
|
||||
scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
|
||||
}
|
||||
pattern := string(scannedBytes)
|
||||
currentLine++
|
||||
// Lines starting with # (comments) are ignored before processing
|
||||
if strings.HasPrefix(pattern, "#") {
|
||||
continue
|
||||
}
|
||||
pattern = strings.TrimSpace(pattern)
|
||||
if pattern == "" {
|
||||
continue
|
||||
}
|
||||
// normalize absolute paths to paths relative to the context
|
||||
// (taking care of '!' prefix)
|
||||
invert := pattern[0] == '!'
|
||||
if invert {
|
||||
pattern = strings.TrimSpace(pattern[1:])
|
||||
}
|
||||
if len(pattern) > 0 {
|
||||
pattern = filepath.Clean(pattern)
|
||||
pattern = filepath.ToSlash(pattern)
|
||||
if len(pattern) > 1 && pattern[0] == '/' {
|
||||
pattern = pattern[1:]
|
||||
}
|
||||
}
|
||||
if invert {
|
||||
pattern = "!" + pattern
|
||||
}
|
||||
|
||||
excludes = append(excludes, pattern)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, errors.Wrap(err, "error reading .dockerignore")
|
||||
}
|
||||
return excludes, nil
|
||||
}
|
||||
14
vendor/github.com/moby/buildkit/frontend/dockerfile/dockerignore/dockerignore_deprecated.go
generated
vendored
Normal file
14
vendor/github.com/moby/buildkit/frontend/dockerfile/dockerignore/dockerignore_deprecated.go
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package dockerignore
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/moby/patternmatcher/ignorefile"
|
||||
)
|
||||
|
||||
// ReadAll is an alias for [ignorefile.ReadAll].
|
||||
//
|
||||
// Deprecated: use [ignorefile.ReadAll] instead.
|
||||
func ReadAll(reader io.Reader) ([]string, error) {
|
||||
return ignorefile.ReadAll(reader)
|
||||
}
|
||||
|
|
@ -239,11 +239,12 @@ func (s *SourcesAndDest) ExpandRaw(expander SingleWordExpander) error {
|
|||
type AddCommand struct {
|
||||
withNameAndCode
|
||||
SourcesAndDest
|
||||
Chown string
|
||||
Chmod string
|
||||
Link bool
|
||||
KeepGitDir bool // whether to keep .git dir, only meaningful for git sources
|
||||
Checksum string
|
||||
Chown string
|
||||
Chmod string
|
||||
Link bool
|
||||
ExcludePatterns []string
|
||||
KeepGitDir bool // whether to keep .git dir, only meaningful for git sources
|
||||
Checksum string
|
||||
}
|
||||
|
||||
func (c *AddCommand) Expand(expander SingleWordExpander) error {
|
||||
|
|
@ -270,10 +271,12 @@ func (c *AddCommand) Expand(expander SingleWordExpander) error {
|
|||
type CopyCommand struct {
|
||||
withNameAndCode
|
||||
SourcesAndDest
|
||||
From string
|
||||
Chown string
|
||||
Chmod string
|
||||
Link bool
|
||||
From string
|
||||
Chown string
|
||||
Chmod string
|
||||
Link bool
|
||||
ExcludePatterns []string
|
||||
Parents bool // parents preserves directory structure
|
||||
}
|
||||
|
||||
func (c *CopyCommand) Expand(expander SingleWordExpander) error {
|
||||
|
|
|
|||
8
vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/exclude_pattern_feature.go
generated
vendored
Normal file
8
vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/exclude_pattern_feature.go
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
//go:build dfexcludepatterns
|
||||
// +build dfexcludepatterns
|
||||
|
||||
package instructions
|
||||
|
||||
func init() {
|
||||
excludePatternsEnabled = true
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var excludePatternsEnabled = false
|
||||
|
||||
type parseRequest struct {
|
||||
command string
|
||||
args []string
|
||||
|
|
@ -34,6 +36,8 @@ type parseRequest struct {
|
|||
var parseRunPreHooks []func(*RunCommand, parseRequest) error
|
||||
var parseRunPostHooks []func(*RunCommand, parseRequest) error
|
||||
|
||||
var parentsEnabled = false
|
||||
|
||||
func nodeArgs(node *parser.Node) []string {
|
||||
result := []string{}
|
||||
for ; node.Next != nil; node = node.Next {
|
||||
|
|
@ -278,10 +282,26 @@ func parseSourcesAndDest(req parseRequest, command string) (*SourcesAndDest, err
|
|||
}, nil
|
||||
}
|
||||
|
||||
func stringValuesFromFlagIfPossible(f *Flag) []string {
|
||||
if f == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return f.StringValues
|
||||
}
|
||||
|
||||
func parseAdd(req parseRequest) (*AddCommand, error) {
|
||||
if len(req.args) < 2 {
|
||||
return nil, errNoDestinationArgument("ADD")
|
||||
}
|
||||
|
||||
var flExcludes *Flag
|
||||
|
||||
// silently ignore if not -labs
|
||||
if excludePatternsEnabled {
|
||||
flExcludes = req.flags.AddStrings("exclude")
|
||||
}
|
||||
|
||||
flChown := req.flags.AddString("chown", "")
|
||||
flChmod := req.flags.AddString("chmod", "")
|
||||
flLink := req.flags.AddBool("link", false)
|
||||
|
|
@ -304,6 +324,7 @@ func parseAdd(req parseRequest) (*AddCommand, error) {
|
|||
Link: flLink.Value == "true",
|
||||
KeepGitDir: flKeepGitDir.Value == "true",
|
||||
Checksum: flChecksum.Value,
|
||||
ExcludePatterns: stringValuesFromFlagIfPossible(flExcludes),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -311,10 +332,22 @@ func parseCopy(req parseRequest) (*CopyCommand, error) {
|
|||
if len(req.args) < 2 {
|
||||
return nil, errNoDestinationArgument("COPY")
|
||||
}
|
||||
|
||||
var flExcludes *Flag
|
||||
var flParents *Flag
|
||||
|
||||
if excludePatternsEnabled {
|
||||
flExcludes = req.flags.AddStrings("exclude")
|
||||
}
|
||||
if parentsEnabled {
|
||||
flParents = req.flags.AddBool("parents", false)
|
||||
}
|
||||
|
||||
flChown := req.flags.AddString("chown", "")
|
||||
flFrom := req.flags.AddString("from", "")
|
||||
flChmod := req.flags.AddString("chmod", "")
|
||||
flLink := req.flags.AddBool("link", false)
|
||||
|
||||
if err := req.flags.Parse(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -331,6 +364,8 @@ func parseCopy(req parseRequest) (*CopyCommand, error) {
|
|||
Chown: flChown.Value,
|
||||
Chmod: flChmod.Value,
|
||||
Link: flLink.Value == "true",
|
||||
Parents: flParents != nil && flParents.Value == "true",
|
||||
ExcludePatterns: stringValuesFromFlagIfPossible(flExcludes),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
8
vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse_parents.go
generated
vendored
Normal file
8
vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse_parents.go
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
//go:build dfparents
|
||||
// +build dfparents
|
||||
|
||||
package instructions
|
||||
|
||||
func init() {
|
||||
parentsEnabled = true
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
// ErrorLocation gives a location in source code that caused the error
|
||||
type ErrorLocation struct {
|
||||
Location []Range
|
||||
Locations [][]Range
|
||||
error
|
||||
}
|
||||
|
||||
|
|
@ -39,11 +39,12 @@ func WithLocation(err error, location []Range) error {
|
|||
}
|
||||
var el *ErrorLocation
|
||||
if errors.As(err, &el) {
|
||||
el.Locations = append(el.Locations, location)
|
||||
return err
|
||||
}
|
||||
return stack.Enable(&ErrorLocation{
|
||||
error: err,
|
||||
Location: location,
|
||||
error: err,
|
||||
Locations: [][]Range{location},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package shell
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/scanner"
|
||||
"unicode"
|
||||
|
|
@ -100,7 +101,7 @@ type shellWord struct {
|
|||
}
|
||||
|
||||
func (sw *shellWord) process(source string) (string, []string, error) {
|
||||
word, words, err := sw.processStopOn(scanner.EOF)
|
||||
word, words, err := sw.processStopOn(scanner.EOF, sw.rawEscapes)
|
||||
if err != nil {
|
||||
err = errors.Wrapf(err, "failed to process %q", source)
|
||||
}
|
||||
|
|
@ -154,7 +155,7 @@ func (w *wordsStruct) getWords() []string {
|
|||
|
||||
// Process the word, starting at 'pos', and stop when we get to the
|
||||
// end of the word or the 'stopChar' character
|
||||
func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) {
|
||||
func (sw *shellWord) processStopOn(stopChar rune, rawEscapes bool) (string, []string, error) {
|
||||
var result bytes.Buffer
|
||||
var words wordsStruct
|
||||
|
||||
|
|
@ -166,6 +167,14 @@ func (sw *shellWord) processStopOn(stopChar rune) (string, []string, error) {
|
|||
charFuncMapping['"'] = sw.processDoubleQuote
|
||||
}
|
||||
|
||||
// temporarily set sw.rawEscapes if needed
|
||||
if rawEscapes != sw.rawEscapes {
|
||||
sw.rawEscapes = rawEscapes
|
||||
defer func() {
|
||||
sw.rawEscapes = !rawEscapes
|
||||
}()
|
||||
}
|
||||
|
||||
for sw.scanner.Peek() != scanner.EOF {
|
||||
ch := sw.scanner.Peek()
|
||||
|
||||
|
|
@ -351,8 +360,9 @@ func (sw *shellWord) processDollar() (string, error) {
|
|||
ch = sw.scanner.Next()
|
||||
chs += string(ch)
|
||||
fallthrough
|
||||
case '+', '-', '?':
|
||||
word, _, err := sw.processStopOn('}')
|
||||
case '+', '-', '?', '#', '%':
|
||||
rawEscapes := ch == '#' || ch == '%'
|
||||
word, _, err := sw.processStopOn('}', rawEscapes)
|
||||
if err != nil {
|
||||
if sw.scanner.Peek() == scanner.EOF {
|
||||
return "", errors.New("syntax error: missing '}'")
|
||||
|
|
@ -394,9 +404,60 @@ func (sw *shellWord) processDollar() (string, error) {
|
|||
return "", errors.Errorf("%s: %s", name, message)
|
||||
}
|
||||
return value, nil
|
||||
case '%', '#':
|
||||
// %/# matches the shortest pattern expansion, %%/## the longest
|
||||
greedy := false
|
||||
if word[0] == byte(ch) {
|
||||
greedy = true
|
||||
word = word[1:]
|
||||
}
|
||||
|
||||
if ch == '%' {
|
||||
return trimSuffix(word, value, greedy)
|
||||
}
|
||||
return trimPrefix(word, value, greedy)
|
||||
default:
|
||||
return "", errors.Errorf("unsupported modifier (%s) in substitution", chs)
|
||||
}
|
||||
case '/':
|
||||
replaceAll := sw.scanner.Peek() == '/'
|
||||
if replaceAll {
|
||||
sw.scanner.Next()
|
||||
}
|
||||
|
||||
pattern, _, err := sw.processStopOn('/', true)
|
||||
if err != nil {
|
||||
if sw.scanner.Peek() == scanner.EOF {
|
||||
return "", errors.New("syntax error: missing '/' in ${}")
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
replacement, _, err := sw.processStopOn('}', true)
|
||||
if err != nil {
|
||||
if sw.scanner.Peek() == scanner.EOF {
|
||||
return "", errors.New("syntax error: missing '}'")
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
value, set := sw.getEnv(name)
|
||||
if sw.skipUnsetEnv && !set {
|
||||
return fmt.Sprintf("${%s/%s/%s}", name, pattern, replacement), nil
|
||||
}
|
||||
|
||||
re, err := convertShellPatternToRegex(pattern, true, false)
|
||||
if err != nil {
|
||||
return "", errors.Errorf("invalid pattern (%s) in substitution: %s", pattern, err)
|
||||
}
|
||||
if replaceAll {
|
||||
value = re.ReplaceAllString(value, replacement)
|
||||
} else {
|
||||
if idx := re.FindStringIndex(value); idx != nil {
|
||||
value = value[0:idx[0]] + replacement + value[idx[1]:]
|
||||
}
|
||||
}
|
||||
return value, nil
|
||||
default:
|
||||
return "", errors.Errorf("unsupported modifier (%s) in substitution", chs)
|
||||
}
|
||||
|
|
@ -472,3 +533,113 @@ func BuildEnvs(env []string) map[string]string {
|
|||
|
||||
return envs
|
||||
}
|
||||
|
||||
// convertShellPatternToRegex converts a shell-like wildcard pattern
|
||||
// (? is a single char, * either the shortest or longest (greedy) string)
|
||||
// to an equivalent regular expression.
|
||||
//
|
||||
// Based on
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13
|
||||
// but without the bracket expressions (`[]`)
|
||||
func convertShellPatternToRegex(pattern string, greedy bool, anchored bool) (*regexp.Regexp, error) {
|
||||
var s scanner.Scanner
|
||||
s.Init(strings.NewReader(pattern))
|
||||
var out strings.Builder
|
||||
out.Grow(len(pattern) + 4)
|
||||
|
||||
// match only at the beginning of the string
|
||||
if anchored {
|
||||
out.WriteByte('^')
|
||||
}
|
||||
|
||||
// default: non-greedy wildcards
|
||||
starPattern := ".*?"
|
||||
if greedy {
|
||||
starPattern = ".*"
|
||||
}
|
||||
|
||||
for tok := s.Next(); tok != scanner.EOF; tok = s.Next() {
|
||||
switch tok {
|
||||
case '*':
|
||||
out.WriteString(starPattern)
|
||||
continue
|
||||
case '?':
|
||||
out.WriteByte('.')
|
||||
continue
|
||||
case '\\':
|
||||
// } and / as part of ${} need to be escaped, but the escape isn't part
|
||||
// of the pattern
|
||||
if s.Peek() == '}' || s.Peek() == '/' {
|
||||
continue
|
||||
}
|
||||
out.WriteRune('\\')
|
||||
tok = s.Next()
|
||||
if tok != '*' && tok != '?' && tok != '\\' {
|
||||
return nil, errors.Errorf("invalid escape '\\%c'", tok)
|
||||
}
|
||||
// regex characters that need to be escaped
|
||||
// escaping closing is optional, but done for consistency
|
||||
case '[', ']', '{', '}', '.', '+', '(', ')', '|', '^', '$':
|
||||
out.WriteByte('\\')
|
||||
}
|
||||
out.WriteRune(tok)
|
||||
}
|
||||
return regexp.Compile(out.String())
|
||||
}
|
||||
|
||||
func trimPrefix(word, value string, greedy bool) (string, error) {
|
||||
re, err := convertShellPatternToRegex(word, greedy, true)
|
||||
if err != nil {
|
||||
return "", errors.Errorf("invalid pattern (%s) in substitution: %s", word, err)
|
||||
}
|
||||
|
||||
if idx := re.FindStringIndex(value); idx != nil {
|
||||
value = value[idx[1]:]
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// reverse without avoid reversing escapes, i.e. a\*c -> c\*a
|
||||
func reversePattern(pattern string) string {
|
||||
patternRunes := []rune(pattern)
|
||||
out := make([]rune, len(patternRunes))
|
||||
lastIdx := len(patternRunes) - 1
|
||||
for i := 0; i <= lastIdx; {
|
||||
tok := patternRunes[i]
|
||||
outIdx := lastIdx - i
|
||||
if tok == '\\' && i != lastIdx {
|
||||
out[outIdx-1] = tok
|
||||
// the pattern is taken from a ${var#pattern}, so the last
|
||||
// character can't be an escape character
|
||||
out[outIdx] = patternRunes[i+1]
|
||||
i += 2
|
||||
} else {
|
||||
out[outIdx] = tok
|
||||
i++
|
||||
}
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func reverseString(str string) string {
|
||||
out := []rune(str)
|
||||
outIdx := len(out) - 1
|
||||
for i := 0; i < outIdx; i++ {
|
||||
out[i], out[outIdx] = out[outIdx], out[i]
|
||||
outIdx--
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func trimSuffix(pattern, word string, greedy bool) (string, error) {
|
||||
// regular expressions can't handle finding the shortest rightmost
|
||||
// string so we reverse both search space and pattern to convert it
|
||||
// to a leftmost search in both cases
|
||||
pattern = reversePattern(pattern)
|
||||
word = reverseString(word)
|
||||
str, err := trimPrefix(pattern, word, greedy)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return reverseString(str), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v3.11.4
|
||||
// source: stack.proto
|
||||
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@ syntax = "proto3";
|
|||
package stack;
|
||||
|
||||
message Stack {
|
||||
repeated Frame frames = 1;
|
||||
repeated string cmdline = 2;
|
||||
int32 pid = 3;
|
||||
string version = 4;
|
||||
string revision = 5;
|
||||
repeated Frame frames = 1;
|
||||
repeated string cmdline = 2;
|
||||
int32 pid = 3;
|
||||
string version = 4;
|
||||
string revision = 5;
|
||||
}
|
||||
|
||||
message Frame {
|
||||
string Name = 1;
|
||||
string File = 2;
|
||||
int32 Line = 3;
|
||||
string Name = 1;
|
||||
string File = 2;
|
||||
int32 Line = 3;
|
||||
}
|
||||
|
|
@ -5,15 +5,19 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// GetMountsFromReader retrieves a list of mounts from the
|
||||
// reader provided, with an optional filter applied (use nil
|
||||
// for no filter). This can be useful in tests or benchmarks
|
||||
// that provide fake mountinfo data, or when a source other
|
||||
// than /proc/self/mountinfo needs to be read from.
|
||||
// than /proc/thread-self/mountinfo needs to be read from.
|
||||
//
|
||||
// This function is Linux-specific.
|
||||
func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
||||
|
|
@ -127,8 +131,40 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
||||
f, err := os.Open("/proc/self/mountinfo")
|
||||
var (
|
||||
haveProcThreadSelf bool
|
||||
haveProcThreadSelfOnce sync.Once
|
||||
)
|
||||
|
||||
func parseMountTable(filter FilterFunc) (_ []*Info, err error) {
|
||||
haveProcThreadSelfOnce.Do(func() {
|
||||
_, err := os.Stat("/proc/thread-self/mountinfo")
|
||||
haveProcThreadSelf = err == nil
|
||||
})
|
||||
|
||||
// We need to lock ourselves to the current OS thread in order to make sure
|
||||
// that the thread referenced by /proc/thread-self stays alive until we
|
||||
// finish parsing the file.
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
var f *os.File
|
||||
if haveProcThreadSelf {
|
||||
f, err = os.Open("/proc/thread-self/mountinfo")
|
||||
} else {
|
||||
// On pre-3.17 kernels (such as CentOS 7), we don't have
|
||||
// /proc/thread-self/ so we need to manually construct
|
||||
// /proc/self/task/<tid>/ as a fallback.
|
||||
f, err = os.Open("/proc/self/task/" + strconv.Itoa(unix.Gettid()) + "/mountinfo")
|
||||
if os.IsNotExist(err) {
|
||||
// If /proc/self/task/... failed, it means that our active pid
|
||||
// namespace doesn't match the pid namespace of the /proc mount. In
|
||||
// this case we just have to make do with /proc/self, since there
|
||||
// is no other way of figuring out our tid in a parent pid
|
||||
// namespace on pre-3.17 kernels.
|
||||
f, err = os.Open("/proc/self/mountinfo")
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -158,10 +194,10 @@ func PidMountInfo(pid int) ([]*Info, error) {
|
|||
// A few specific characters in mountinfo path entries (root and mountpoint)
|
||||
// are escaped using a backslash followed by a character's ascii code in octal.
|
||||
//
|
||||
// space -- as \040
|
||||
// tab (aka \t) -- as \011
|
||||
// newline (aka \n) -- as \012
|
||||
// backslash (aka \\) -- as \134
|
||||
// space -- as \040
|
||||
// tab (aka \t) -- as \011
|
||||
// newline (aka \n) -- as \012
|
||||
// backslash (aka \\) -- as \134
|
||||
//
|
||||
// This function converts path from mountinfo back, i.e. it unescapes the above sequences.
|
||||
func unescape(path string) (string, error) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
// Package term provides structures and helper functions to work with
|
||||
// terminal (state, sizes).
|
||||
package term
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package term
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func tcget(fd uintptr) (*Termios, error) {
|
||||
p, err := unix.IoctlGetTermios(int(fd), getTermios)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func tcset(fd uintptr, p *Termios) error {
|
||||
return unix.IoctlSetTermios(int(fd), setTermios, p)
|
||||
}
|
||||
|
|
@ -1,100 +1,85 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
// Package term provides structures and helper functions to work with
|
||||
// terminal (state, sizes).
|
||||
package term
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
import "io"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// ErrInvalidState is returned if the state of the terminal is invalid.
|
||||
var ErrInvalidState = errors.New("Invalid terminal state")
|
||||
|
||||
// State represents the state of the terminal.
|
||||
type State struct {
|
||||
termios Termios
|
||||
}
|
||||
// State holds the platform-specific state / console mode for the terminal.
|
||||
type State terminalState
|
||||
|
||||
// Winsize represents the size of the terminal window.
|
||||
type Winsize struct {
|
||||
Height uint16
|
||||
Width uint16
|
||||
x uint16
|
||||
y uint16
|
||||
|
||||
// Only used on Unix
|
||||
x uint16
|
||||
y uint16
|
||||
}
|
||||
|
||||
// StdStreams returns the standard streams (stdin, stdout, stderr).
|
||||
//
|
||||
// On Windows, it attempts to turn on VT handling on all std handles if
|
||||
// supported, or falls back to terminal emulation. On Unix, this returns
|
||||
// the standard [os.Stdin], [os.Stdout] and [os.Stderr].
|
||||
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
return os.Stdin, os.Stdout, os.Stderr
|
||||
return stdStreams()
|
||||
}
|
||||
|
||||
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
|
||||
func GetFdInfo(in interface{}) (uintptr, bool) {
|
||||
var inFd uintptr
|
||||
var isTerminalIn bool
|
||||
if file, ok := in.(*os.File); ok {
|
||||
inFd = file.Fd()
|
||||
isTerminalIn = IsTerminal(inFd)
|
||||
}
|
||||
return inFd, isTerminalIn
|
||||
func GetFdInfo(in interface{}) (fd uintptr, isTerminal bool) {
|
||||
return getFdInfo(in)
|
||||
}
|
||||
|
||||
// GetWinsize returns the window size based on the specified file descriptor.
|
||||
func GetWinsize(fd uintptr) (*Winsize, error) {
|
||||
return getWinsize(fd)
|
||||
}
|
||||
|
||||
// SetWinsize tries to set the specified window size for the specified file
|
||||
// descriptor. It is only implemented on Unix, and returns an error on Windows.
|
||||
func SetWinsize(fd uintptr, ws *Winsize) error {
|
||||
return setWinsize(fd, ws)
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
_, err := tcget(fd)
|
||||
return err == nil
|
||||
return isTerminal(fd)
|
||||
}
|
||||
|
||||
// RestoreTerminal restores the terminal connected to the given file descriptor
|
||||
// to a previous state.
|
||||
func RestoreTerminal(fd uintptr, state *State) error {
|
||||
if state == nil {
|
||||
return ErrInvalidState
|
||||
}
|
||||
return tcset(fd, &state.termios)
|
||||
return restoreTerminal(fd, state)
|
||||
}
|
||||
|
||||
// SaveState saves the state of the terminal connected to the given file descriptor.
|
||||
func SaveState(fd uintptr) (*State, error) {
|
||||
termios, err := tcget(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &State{termios: *termios}, nil
|
||||
return saveState(fd)
|
||||
}
|
||||
|
||||
// DisableEcho applies the specified state to the terminal connected to the file
|
||||
// descriptor, with echo disabled.
|
||||
func DisableEcho(fd uintptr, state *State) error {
|
||||
newState := state.termios
|
||||
newState.Lflag &^= unix.ECHO
|
||||
|
||||
if err := tcset(fd, &newState); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return disableEcho(fd, state)
|
||||
}
|
||||
|
||||
// SetRawTerminal puts the terminal connected to the given file descriptor into
|
||||
// raw mode and returns the previous state. On UNIX, this puts both the input
|
||||
// and output into raw mode. On Windows, it only puts the input into raw mode.
|
||||
func SetRawTerminal(fd uintptr) (*State, error) {
|
||||
oldState, err := MakeRaw(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return oldState, err
|
||||
// raw mode and returns the previous state. On UNIX, this is the equivalent of
|
||||
// [MakeRaw], and puts both the input and output into raw mode. On Windows, it
|
||||
// only puts the input into raw mode.
|
||||
func SetRawTerminal(fd uintptr) (previousState *State, err error) {
|
||||
return setRawTerminal(fd)
|
||||
}
|
||||
|
||||
// SetRawTerminalOutput puts the output of terminal connected to the given file
|
||||
// descriptor into raw mode. On UNIX, this does nothing and returns nil for the
|
||||
// state. On Windows, it disables LF -> CRLF translation.
|
||||
func SetRawTerminalOutput(fd uintptr) (*State, error) {
|
||||
return nil, nil
|
||||
func SetRawTerminalOutput(fd uintptr) (previousState *State, err error) {
|
||||
return setRawTerminalOutput(fd)
|
||||
}
|
||||
|
||||
// MakeRaw puts the terminal (Windows Console) connected to the
|
||||
// given file descriptor into raw mode and returns the previous state of
|
||||
// the terminal so that it can be restored.
|
||||
func MakeRaw(fd uintptr) (previousState *State, err error) {
|
||||
return makeRaw(fd)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package term
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// ErrInvalidState is returned if the state of the terminal is invalid.
|
||||
//
|
||||
// Deprecated: ErrInvalidState is no longer used.
|
||||
var ErrInvalidState = errors.New("Invalid terminal state")
|
||||
|
||||
// terminalState holds the platform-specific state / console mode for the terminal.
|
||||
type terminalState struct {
|
||||
termios unix.Termios
|
||||
}
|
||||
|
||||
func stdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
return os.Stdin, os.Stdout, os.Stderr
|
||||
}
|
||||
|
||||
func getFdInfo(in interface{}) (uintptr, bool) {
|
||||
var inFd uintptr
|
||||
var isTerminalIn bool
|
||||
if file, ok := in.(*os.File); ok {
|
||||
inFd = file.Fd()
|
||||
isTerminalIn = isTerminal(inFd)
|
||||
}
|
||||
return inFd, isTerminalIn
|
||||
}
|
||||
|
||||
func getWinsize(fd uintptr) (*Winsize, error) {
|
||||
uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
|
||||
ws := &Winsize{Height: uws.Row, Width: uws.Col, x: uws.Xpixel, y: uws.Ypixel}
|
||||
return ws, err
|
||||
}
|
||||
|
||||
func setWinsize(fd uintptr, ws *Winsize) error {
|
||||
return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &unix.Winsize{
|
||||
Row: ws.Height,
|
||||
Col: ws.Width,
|
||||
Xpixel: ws.x,
|
||||
Ypixel: ws.y,
|
||||
})
|
||||
}
|
||||
|
||||
func isTerminal(fd uintptr) bool {
|
||||
_, err := tcget(fd)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func restoreTerminal(fd uintptr, state *State) error {
|
||||
if state == nil {
|
||||
return errors.New("invalid terminal state")
|
||||
}
|
||||
return tcset(fd, &state.termios)
|
||||
}
|
||||
|
||||
func saveState(fd uintptr) (*State, error) {
|
||||
termios, err := tcget(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &State{termios: *termios}, nil
|
||||
}
|
||||
|
||||
func disableEcho(fd uintptr, state *State) error {
|
||||
newState := state.termios
|
||||
newState.Lflag &^= unix.ECHO
|
||||
|
||||
return tcset(fd, &newState)
|
||||
}
|
||||
|
||||
func setRawTerminal(fd uintptr) (*State, error) {
|
||||
return makeRaw(fd)
|
||||
}
|
||||
|
||||
func setRawTerminalOutput(fd uintptr) (*State, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func tcget(fd uintptr) (*unix.Termios, error) {
|
||||
p, err := unix.IoctlGetTermios(int(fd), getTermios)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func tcset(fd uintptr, p *unix.Termios) error {
|
||||
return unix.IoctlSetTermios(int(fd), setTermios, p)
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package term
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
|
@ -9,22 +10,15 @@ import (
|
|||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// State holds the console mode for the terminal.
|
||||
type State struct {
|
||||
// terminalState holds the platform-specific state / console mode for the terminal.
|
||||
type terminalState struct {
|
||||
mode uint32
|
||||
}
|
||||
|
||||
// Winsize is used for window size.
|
||||
type Winsize struct {
|
||||
Height uint16
|
||||
Width uint16
|
||||
}
|
||||
|
||||
// vtInputSupported is true if winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported by the console
|
||||
var vtInputSupported bool
|
||||
|
||||
// StdStreams returns the standard streams (stdin, stdout, stderr).
|
||||
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
func stdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
// Turn on VT handling on all std handles, if possible. This might
|
||||
// fail, in which case we will fall back to terminal emulation.
|
||||
var (
|
||||
|
|
@ -87,16 +81,14 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
|||
stdErr = os.Stderr
|
||||
}
|
||||
|
||||
return
|
||||
return stdIn, stdOut, stdErr
|
||||
}
|
||||
|
||||
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
|
||||
func GetFdInfo(in interface{}) (uintptr, bool) {
|
||||
func getFdInfo(in interface{}) (uintptr, bool) {
|
||||
return windowsconsole.GetHandleInfo(in)
|
||||
}
|
||||
|
||||
// GetWinsize returns the window size based on the specified file descriptor.
|
||||
func GetWinsize(fd uintptr) (*Winsize, error) {
|
||||
func getWinsize(fd uintptr) (*Winsize, error) {
|
||||
var info windows.ConsoleScreenBufferInfo
|
||||
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -110,21 +102,21 @@ func GetWinsize(fd uintptr) (*Winsize, error) {
|
|||
return winsize, nil
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
func setWinsize(fd uintptr, ws *Winsize) error {
|
||||
return fmt.Errorf("not implemented on Windows")
|
||||
}
|
||||
|
||||
func isTerminal(fd uintptr) bool {
|
||||
var mode uint32
|
||||
err := windows.GetConsoleMode(windows.Handle(fd), &mode)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// RestoreTerminal restores the terminal connected to the given file descriptor
|
||||
// to a previous state.
|
||||
func RestoreTerminal(fd uintptr, state *State) error {
|
||||
func restoreTerminal(fd uintptr, state *State) error {
|
||||
return windows.SetConsoleMode(windows.Handle(fd), state.mode)
|
||||
}
|
||||
|
||||
// SaveState saves the state of the terminal connected to the given file descriptor.
|
||||
func SaveState(fd uintptr) (*State, error) {
|
||||
func saveState(fd uintptr) (*State, error) {
|
||||
var mode uint32
|
||||
|
||||
if err := windows.GetConsoleMode(windows.Handle(fd), &mode); err != nil {
|
||||
|
|
@ -134,9 +126,8 @@ func SaveState(fd uintptr) (*State, error) {
|
|||
return &State{mode: mode}, nil
|
||||
}
|
||||
|
||||
// DisableEcho disables echo for the terminal connected to the given file descriptor.
|
||||
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
||||
func DisableEcho(fd uintptr, state *State) error {
|
||||
func disableEcho(fd uintptr, state *State) error {
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
||||
mode := state.mode
|
||||
mode &^= windows.ENABLE_ECHO_INPUT
|
||||
mode |= windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT
|
||||
|
|
@ -150,69 +141,27 @@ func DisableEcho(fd uintptr, state *State) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetRawTerminal puts the terminal connected to the given file descriptor into
|
||||
// raw mode and returns the previous state. On UNIX, this puts both the input
|
||||
// and output into raw mode. On Windows, it only puts the input into raw mode.
|
||||
func SetRawTerminal(fd uintptr) (*State, error) {
|
||||
state, err := MakeRaw(fd)
|
||||
func setRawTerminal(fd uintptr) (*State, error) {
|
||||
oldState, err := MakeRaw(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Register an interrupt handler to catch and restore prior state
|
||||
restoreAtInterrupt(fd, state)
|
||||
return state, err
|
||||
restoreAtInterrupt(fd, oldState)
|
||||
return oldState, err
|
||||
}
|
||||
|
||||
// SetRawTerminalOutput puts the output of terminal connected to the given file
|
||||
// descriptor into raw mode. On UNIX, this does nothing and returns nil for the
|
||||
// state. On Windows, it disables LF -> CRLF translation.
|
||||
func SetRawTerminalOutput(fd uintptr) (*State, error) {
|
||||
state, err := SaveState(fd)
|
||||
func setRawTerminalOutput(fd uintptr) (*State, error) {
|
||||
oldState, err := saveState(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ignore failures, since winterm.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this
|
||||
// version of Windows.
|
||||
_ = windows.SetConsoleMode(windows.Handle(fd), state.mode|windows.DISABLE_NEWLINE_AUTO_RETURN)
|
||||
return state, err
|
||||
}
|
||||
|
||||
// MakeRaw puts the terminal (Windows Console) connected to the given file descriptor into raw
|
||||
// mode and returns the previous state of the terminal so that it can be restored.
|
||||
func MakeRaw(fd uintptr) (*State, error) {
|
||||
state, err := SaveState(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mode := state.mode
|
||||
|
||||
// See
|
||||
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
|
||||
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
||||
|
||||
// Disable these modes
|
||||
mode &^= windows.ENABLE_ECHO_INPUT
|
||||
mode &^= windows.ENABLE_LINE_INPUT
|
||||
mode &^= windows.ENABLE_MOUSE_INPUT
|
||||
mode &^= windows.ENABLE_WINDOW_INPUT
|
||||
mode &^= windows.ENABLE_PROCESSED_INPUT
|
||||
|
||||
// Enable these modes
|
||||
mode |= windows.ENABLE_EXTENDED_FLAGS
|
||||
mode |= windows.ENABLE_INSERT_MODE
|
||||
mode |= windows.ENABLE_QUICK_EDIT_MODE
|
||||
if vtInputSupported {
|
||||
mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
|
||||
}
|
||||
|
||||
err = windows.SetConsoleMode(windows.Handle(fd), mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return state, nil
|
||||
_ = windows.SetConsoleMode(windows.Handle(fd), oldState.mode|windows.DISABLE_NEWLINE_AUTO_RETURN)
|
||||
return oldState, err
|
||||
}
|
||||
|
||||
func restoreAtInterrupt(fd uintptr, state *State) {
|
||||
|
|
|
|||
13
vendor/github.com/moby/term/termios.go → vendor/github.com/moby/term/termios_unix.go
generated
vendored
13
vendor/github.com/moby/term/termios.go → vendor/github.com/moby/term/termios_unix.go
generated
vendored
|
|
@ -8,12 +8,11 @@ import (
|
|||
)
|
||||
|
||||
// Termios is the Unix API for terminal I/O.
|
||||
//
|
||||
// Deprecated: use [unix.Termios].
|
||||
type Termios = unix.Termios
|
||||
|
||||
// MakeRaw puts the terminal connected to the given file descriptor into raw
|
||||
// mode and returns the previous state of the terminal so that it can be
|
||||
// restored.
|
||||
func MakeRaw(fd uintptr) (*State, error) {
|
||||
func makeRaw(fd uintptr) (*State, error) {
|
||||
termios, err := tcget(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -21,10 +20,10 @@ func MakeRaw(fd uintptr) (*State, error) {
|
|||
|
||||
oldState := State{termios: *termios}
|
||||
|
||||
termios.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
|
||||
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
|
||||
termios.Oflag &^= unix.OPOST
|
||||
termios.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
|
||||
termios.Cflag &^= (unix.CSIZE | unix.PARENB)
|
||||
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
|
||||
termios.Cflag &^= unix.CSIZE | unix.PARENB
|
||||
termios.Cflag |= unix.CS8
|
||||
termios.Cc[unix.VMIN] = 1
|
||||
termios.Cc[unix.VTIME] = 0
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package term
|
||||
|
||||
import "golang.org/x/sys/windows"
|
||||
|
||||
func makeRaw(fd uintptr) (*State, error) {
|
||||
state, err := SaveState(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mode := state.mode
|
||||
|
||||
// See
|
||||
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
|
||||
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
||||
|
||||
// Disable these modes
|
||||
mode &^= windows.ENABLE_ECHO_INPUT
|
||||
mode &^= windows.ENABLE_LINE_INPUT
|
||||
mode &^= windows.ENABLE_MOUSE_INPUT
|
||||
mode &^= windows.ENABLE_WINDOW_INPUT
|
||||
mode &^= windows.ENABLE_PROCESSED_INPUT
|
||||
|
||||
// Enable these modes
|
||||
mode |= windows.ENABLE_EXTENDED_FLAGS
|
||||
mode |= windows.ENABLE_INSERT_MODE
|
||||
mode |= windows.ENABLE_QUICK_EDIT_MODE
|
||||
if vtInputSupported {
|
||||
mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
|
||||
}
|
||||
|
||||
err = windows.SetConsoleMode(windows.Handle(fd), mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
|
@ -195,10 +195,10 @@ func keyToString(keyEvent *winterm.KEY_EVENT_RECORD, escapeSequence []byte) stri
|
|||
|
||||
// <Alt>+Key generates ESC N Key
|
||||
if !control && alt {
|
||||
return ansiterm.KEY_ESC_N + strings.ToLower(string(keyEvent.UnicodeChar))
|
||||
return ansiterm.KEY_ESC_N + strings.ToLower(string(rune(keyEvent.UnicodeChar)))
|
||||
}
|
||||
|
||||
return string(keyEvent.UnicodeChar)
|
||||
return string(rune(keyEvent.UnicodeChar))
|
||||
}
|
||||
|
||||
// formatVirtualKey converts a virtual key (e.g., up arrow) into the appropriate ANSI string.
|
||||
|
|
|
|||
|
|
@ -30,8 +30,11 @@ func GetHandleInfo(in interface{}) (uintptr, bool) {
|
|||
|
||||
// IsConsole returns true if the given file descriptor is a Windows Console.
|
||||
// The code assumes that GetConsoleMode will return an error for file descriptors that are not a console.
|
||||
// Deprecated: use golang.org/x/sys/windows.GetConsoleMode() or golang.org/x/term.IsTerminal()
|
||||
var IsConsole = isConsole
|
||||
//
|
||||
// Deprecated: use [windows.GetConsoleMode] or [golang.org/x/term.IsTerminal].
|
||||
func IsConsole(fd uintptr) bool {
|
||||
return isConsole(fd)
|
||||
}
|
||||
|
||||
func isConsole(fd uintptr) bool {
|
||||
var mode uint32
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package term
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// GetWinsize returns the window size based on the specified file descriptor.
|
||||
func GetWinsize(fd uintptr) (*Winsize, error) {
|
||||
uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
|
||||
ws := &Winsize{Height: uws.Row, Width: uws.Col, x: uws.Xpixel, y: uws.Ypixel}
|
||||
return ws, err
|
||||
}
|
||||
|
||||
// SetWinsize tries to set the specified window size for the specified file descriptor.
|
||||
func SetWinsize(fd uintptr, ws *Winsize) error {
|
||||
uws := &unix.Winsize{Row: ws.Height, Col: ws.Width, Xpixel: ws.x, Ypixel: ws.y}
|
||||
return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, uws)
|
||||
}
|
||||
|
|
@ -59,10 +59,4 @@ const (
|
|||
|
||||
// AnnotationBaseImageName is the annotation key for the image reference of the image's base image.
|
||||
AnnotationBaseImageName = "org.opencontainers.image.base.name"
|
||||
|
||||
// AnnotationArtifactCreated is the annotation key for the date and time on which the artifact was built, conforming to RFC 3339.
|
||||
AnnotationArtifactCreated = "org.opencontainers.artifact.created"
|
||||
|
||||
// AnnotationArtifactDescription is the annotation key for the human readable description for the artifact.
|
||||
AnnotationArtifactDescription = "org.opencontainers.artifact.description"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import digest "github.com/opencontainers/go-digest"
|
|||
// when marshalled to JSON.
|
||||
type Descriptor struct {
|
||||
// MediaType is the media type of the object this schema refers to.
|
||||
MediaType string `json:"mediaType,omitempty"`
|
||||
MediaType string `json:"mediaType"`
|
||||
|
||||
// Digest is the digest of the targeted content.
|
||||
Digest digest.Digest `json:"digest"`
|
||||
|
|
@ -52,7 +52,7 @@ type Descriptor struct {
|
|||
// Platform describes the platform which the image in the manifest runs on.
|
||||
type Platform struct {
|
||||
// Architecture field specifies the CPU architecture, for example
|
||||
// `amd64` or `ppc64`.
|
||||
// `amd64` or `ppc64le`.
|
||||
Architecture string `json:"architecture"`
|
||||
|
||||
// OS specifies the operating system, for example `linux` or `windows`.
|
||||
|
|
@ -70,3 +70,11 @@ type Platform struct {
|
|||
// example `v7` to specify ARMv7 when architecture is `arm`.
|
||||
Variant string `json:"variant,omitempty"`
|
||||
}
|
||||
|
||||
// DescriptorEmptyJSON is the descriptor of a blob with content of `{}`.
|
||||
var DescriptorEmptyJSON = Descriptor{
|
||||
MediaType: MediaTypeEmptyJSON,
|
||||
Digest: `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a`,
|
||||
Size: 2,
|
||||
Data: []byte(`{}`),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,15 @@ type Index struct {
|
|||
// MediaType specifies the type of this document data structure e.g. `application/vnd.oci.image.index.v1+json`
|
||||
MediaType string `json:"mediaType,omitempty"`
|
||||
|
||||
// ArtifactType specifies the IANA media type of artifact when the manifest is used for an artifact.
|
||||
ArtifactType string `json:"artifactType,omitempty"`
|
||||
|
||||
// Manifests references platform specific manifests.
|
||||
Manifests []Descriptor `json:"manifests"`
|
||||
|
||||
// Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.
|
||||
Subject *Descriptor `json:"subject,omitempty"`
|
||||
|
||||
// Annotations contains arbitrary metadata for the image index.
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,10 +15,14 @@
|
|||
package v1
|
||||
|
||||
const (
|
||||
// ImageLayoutFile is the file name of oci image layout file
|
||||
// ImageLayoutFile is the file name containing ImageLayout in an OCI Image Layout
|
||||
ImageLayoutFile = "oci-layout"
|
||||
// ImageLayoutVersion is the version of ImageLayout
|
||||
ImageLayoutVersion = "1.0.0"
|
||||
// ImageIndexFile is the file name of the entry point for references and descriptors in an OCI Image Layout
|
||||
ImageIndexFile = "index.json"
|
||||
// ImageBlobsDir is the directory name containing content addressable blobs in an OCI Image Layout
|
||||
ImageBlobsDir = "blobs"
|
||||
)
|
||||
|
||||
// ImageLayout is the structure in the "oci-layout" file, found in the root
|
||||
|
|
|
|||
|
|
@ -39,11 +39,3 @@ type Manifest struct {
|
|||
// Annotations contains arbitrary metadata for the image manifest.
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// ScratchDescriptor is the descriptor of a blob with content of `{}`.
|
||||
var ScratchDescriptor = Descriptor{
|
||||
MediaType: MediaTypeScratch,
|
||||
Digest: `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a`,
|
||||
Size: 2,
|
||||
Data: []byte(`{}`),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,6 @@ const (
|
|||
// MediaTypeImageConfig specifies the media type for the image configuration.
|
||||
MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json"
|
||||
|
||||
// MediaTypeScratch specifies the media type for an unused blob containing the value `{}`
|
||||
MediaTypeScratch = "application/vnd.oci.scratch.v1+json"
|
||||
// MediaTypeEmptyJSON specifies the media type for an unused blob containing the value `{}`
|
||||
MediaTypeEmptyJSON = "application/vnd.oci.empty.v1+json"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const (
|
|||
VersionPatch = 0
|
||||
|
||||
// VersionDev indicates development branch. Releases will be empty string.
|
||||
VersionDev = "-rc.3"
|
||||
VersionDev = "-rc.5"
|
||||
)
|
||||
|
||||
// Version is the specification version that the package types support.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"time"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// Counter is a Metric that represents a single numerical value that only ever
|
||||
|
|
@ -59,6 +60,18 @@ type ExemplarAdder interface {
|
|||
// CounterOpts is an alias for Opts. See there for doc comments.
|
||||
type CounterOpts Opts
|
||||
|
||||
// CounterVecOpts bundles the options to create a CounterVec metric.
|
||||
// It is mandatory to set CounterOpts, see there for mandatory fields. VariableLabels
|
||||
// is optional and can safely be left to its default value.
|
||||
type CounterVecOpts struct {
|
||||
CounterOpts
|
||||
|
||||
// VariableLabels are used to partition the metric vector by the given set
|
||||
// of labels. Each label value will be constrained with the optional Constraint
|
||||
// function, if provided.
|
||||
VariableLabels ConstrainableLabels
|
||||
}
|
||||
|
||||
// NewCounter creates a new Counter based on the provided CounterOpts.
|
||||
//
|
||||
// The returned implementation also implements ExemplarAdder. It is safe to
|
||||
|
|
@ -78,8 +91,12 @@ func NewCounter(opts CounterOpts) Counter {
|
|||
nil,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
result := &counter{desc: desc, labelPairs: desc.constLabelPairs, now: time.Now}
|
||||
if opts.now == nil {
|
||||
opts.now = time.Now
|
||||
}
|
||||
result := &counter{desc: desc, labelPairs: desc.constLabelPairs, now: opts.now}
|
||||
result.init(result) // Init self-collection.
|
||||
result.createdTs = timestamppb.New(opts.now())
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
@ -94,10 +111,12 @@ type counter struct {
|
|||
selfCollector
|
||||
desc *Desc
|
||||
|
||||
createdTs *timestamppb.Timestamp
|
||||
labelPairs []*dto.LabelPair
|
||||
exemplar atomic.Value // Containing nil or a *dto.Exemplar.
|
||||
|
||||
now func() time.Time // To mock out time.Now() for testing.
|
||||
// now is for testing purposes, by default it's time.Now.
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
func (c *counter) Desc() *Desc {
|
||||
|
|
@ -147,8 +166,7 @@ func (c *counter) Write(out *dto.Metric) error {
|
|||
exemplar = e.(*dto.Exemplar)
|
||||
}
|
||||
val := c.get()
|
||||
|
||||
return populateMetric(CounterValue, val, c.labelPairs, exemplar, out)
|
||||
return populateMetric(CounterValue, val, c.labelPairs, exemplar, out, c.createdTs)
|
||||
}
|
||||
|
||||
func (c *counter) updateExemplar(v float64, l Labels) {
|
||||
|
|
@ -174,19 +192,31 @@ type CounterVec struct {
|
|||
// NewCounterVec creates a new CounterVec based on the provided CounterOpts and
|
||||
// partitioned by the given label names.
|
||||
func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
|
||||
desc := NewDesc(
|
||||
return V2.NewCounterVec(CounterVecOpts{
|
||||
CounterOpts: opts,
|
||||
VariableLabels: UnconstrainedLabels(labelNames),
|
||||
})
|
||||
}
|
||||
|
||||
// NewCounterVec creates a new CounterVec based on the provided CounterVecOpts.
|
||||
func (v2) NewCounterVec(opts CounterVecOpts) *CounterVec {
|
||||
desc := V2.NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
labelNames,
|
||||
opts.VariableLabels,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
if opts.now == nil {
|
||||
opts.now = time.Now
|
||||
}
|
||||
return &CounterVec{
|
||||
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
|
||||
if len(lvs) != len(desc.variableLabels) {
|
||||
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
|
||||
if len(lvs) != len(desc.variableLabels.names) {
|
||||
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels.names, lvs))
|
||||
}
|
||||
result := &counter{desc: desc, labelPairs: MakeLabelPairs(desc, lvs), now: time.Now}
|
||||
result := &counter{desc: desc, labelPairs: MakeLabelPairs(desc, lvs), now: opts.now}
|
||||
result.init(result) // Init self-collection.
|
||||
result.createdTs = timestamppb.New(opts.now())
|
||||
return result
|
||||
}),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,20 +14,16 @@
|
|||
package prometheus
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/cespare/xxhash/v2"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"github.com/prometheus/common/model"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/internal"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
// Desc is the descriptor used by every Prometheus Metric. It is essentially
|
||||
|
|
@ -54,9 +50,9 @@ type Desc struct {
|
|||
// constLabelPairs contains precalculated DTO label pairs based on
|
||||
// the constant labels.
|
||||
constLabelPairs []*dto.LabelPair
|
||||
// variableLabels contains names of labels for which the metric
|
||||
// maintains variable values.
|
||||
variableLabels []string
|
||||
// variableLabels contains names of labels and normalization function for
|
||||
// which the metric maintains variable values.
|
||||
variableLabels *compiledLabels
|
||||
// id is a hash of the values of the ConstLabels and fqName. This
|
||||
// must be unique among all registered descriptors and can therefore be
|
||||
// used as an identifier of the descriptor.
|
||||
|
|
@ -80,10 +76,24 @@ type Desc struct {
|
|||
// For constLabels, the label values are constant. Therefore, they are fully
|
||||
// specified in the Desc. See the Collector example for a usage pattern.
|
||||
func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *Desc {
|
||||
return V2.NewDesc(fqName, help, UnconstrainedLabels(variableLabels), constLabels)
|
||||
}
|
||||
|
||||
// NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc
|
||||
// and will be reported on registration time. variableLabels and constLabels can
|
||||
// be nil if no such labels should be set. fqName must not be empty.
|
||||
//
|
||||
// variableLabels only contain the label names and normalization functions. Their
|
||||
// label values are variable and therefore not part of the Desc. (They are managed
|
||||
// within the Metric.)
|
||||
//
|
||||
// For constLabels, the label values are constant. Therefore, they are fully
|
||||
// specified in the Desc. See the Collector example for a usage pattern.
|
||||
func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels) *Desc {
|
||||
d := &Desc{
|
||||
fqName: fqName,
|
||||
help: help,
|
||||
variableLabels: variableLabels,
|
||||
variableLabels: variableLabels.compile(),
|
||||
}
|
||||
if !model.IsValidMetricName(model.LabelValue(fqName)) {
|
||||
d.err = fmt.Errorf("%q is not a valid metric name", fqName)
|
||||
|
|
@ -93,7 +103,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *
|
|||
// their sorted label names) plus the fqName (at position 0).
|
||||
labelValues := make([]string, 1, len(constLabels)+1)
|
||||
labelValues[0] = fqName
|
||||
labelNames := make([]string, 0, len(constLabels)+len(variableLabels))
|
||||
labelNames := make([]string, 0, len(constLabels)+len(d.variableLabels.names))
|
||||
labelNameSet := map[string]struct{}{}
|
||||
// First add only the const label names and sort them...
|
||||
for labelName := range constLabels {
|
||||
|
|
@ -118,16 +128,16 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *
|
|||
// Now add the variable label names, but prefix them with something that
|
||||
// cannot be in a regular label name. That prevents matching the label
|
||||
// dimension with a different mix between preset and variable labels.
|
||||
for _, labelName := range variableLabels {
|
||||
if !checkLabelName(labelName) {
|
||||
d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName)
|
||||
for _, label := range d.variableLabels.names {
|
||||
if !checkLabelName(label) {
|
||||
d.err = fmt.Errorf("%q is not a valid label name for metric %q", label, fqName)
|
||||
return d
|
||||
}
|
||||
labelNames = append(labelNames, "$"+labelName)
|
||||
labelNameSet[labelName] = struct{}{}
|
||||
labelNames = append(labelNames, "$"+label)
|
||||
labelNameSet[label] = struct{}{}
|
||||
}
|
||||
if len(labelNames) != len(labelNameSet) {
|
||||
d.err = errors.New("duplicate label names")
|
||||
d.err = fmt.Errorf("duplicate label names in constant and variable labels for metric %q", fqName)
|
||||
return d
|
||||
}
|
||||
|
||||
|
|
@ -179,11 +189,19 @@ func (d *Desc) String() string {
|
|||
fmt.Sprintf("%s=%q", lp.GetName(), lp.GetValue()),
|
||||
)
|
||||
}
|
||||
vlStrings := make([]string, 0, len(d.variableLabels.names))
|
||||
for _, vl := range d.variableLabels.names {
|
||||
if fn, ok := d.variableLabels.labelConstraints[vl]; ok && fn != nil {
|
||||
vlStrings = append(vlStrings, fmt.Sprintf("c(%s)", vl))
|
||||
} else {
|
||||
vlStrings = append(vlStrings, vl)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: %v}",
|
||||
"Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: {%s}}",
|
||||
d.fqName,
|
||||
d.help,
|
||||
strings.Join(lpStrings, ","),
|
||||
d.variableLabels,
|
||||
strings.Join(vlStrings, ","),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,35 +37,35 @@
|
|||
//
|
||||
// type metrics struct {
|
||||
// cpuTemp prometheus.Gauge
|
||||
// hdFailures *prometheus.CounterVec
|
||||
// hdFailures *prometheus.CounterVec
|
||||
// }
|
||||
//
|
||||
// func NewMetrics(reg prometheus.Registerer) *metrics {
|
||||
// m := &metrics{
|
||||
// cpuTemp: prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
// Name: "cpu_temperature_celsius",
|
||||
// Help: "Current temperature of the CPU.",
|
||||
// }),
|
||||
// hdFailures: prometheus.NewCounterVec(
|
||||
// prometheus.CounterOpts{
|
||||
// Name: "hd_errors_total",
|
||||
// Help: "Number of hard-disk errors.",
|
||||
// },
|
||||
// []string{"device"},
|
||||
// ),
|
||||
// }
|
||||
// reg.MustRegister(m.cpuTemp)
|
||||
// reg.MustRegister(m.hdFailures)
|
||||
// return m
|
||||
// m := &metrics{
|
||||
// cpuTemp: prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
// Name: "cpu_temperature_celsius",
|
||||
// Help: "Current temperature of the CPU.",
|
||||
// }),
|
||||
// hdFailures: prometheus.NewCounterVec(
|
||||
// prometheus.CounterOpts{
|
||||
// Name: "hd_errors_total",
|
||||
// Help: "Number of hard-disk errors.",
|
||||
// },
|
||||
// []string{"device"},
|
||||
// ),
|
||||
// }
|
||||
// reg.MustRegister(m.cpuTemp)
|
||||
// reg.MustRegister(m.hdFailures)
|
||||
// return m
|
||||
// }
|
||||
//
|
||||
// func main() {
|
||||
// // Create a non-global registry.
|
||||
// reg := prometheus.NewRegistry()
|
||||
// // Create a non-global registry.
|
||||
// reg := prometheus.NewRegistry()
|
||||
//
|
||||
// // Create new metrics and register them using the custom registry.
|
||||
// m := NewMetrics(reg)
|
||||
// // Set values for the new created metrics.
|
||||
// // Create new metrics and register them using the custom registry.
|
||||
// m := NewMetrics(reg)
|
||||
// // Set values for the new created metrics.
|
||||
// m.cpuTemp.Set(65.3)
|
||||
// m.hdFailures.With(prometheus.Labels{"device":"/dev/sda"}).Inc()
|
||||
//
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ func (e *expvarCollector) Collect(ch chan<- Metric) {
|
|||
continue
|
||||
}
|
||||
var v interface{}
|
||||
labels := make([]string, len(desc.variableLabels))
|
||||
labels := make([]string, len(desc.variableLabels.names))
|
||||
if err := json.Unmarshal([]byte(expVar.String()), &v); err != nil {
|
||||
ch <- NewInvalidMetric(desc, err)
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -55,6 +55,18 @@ type Gauge interface {
|
|||
// GaugeOpts is an alias for Opts. See there for doc comments.
|
||||
type GaugeOpts Opts
|
||||
|
||||
// GaugeVecOpts bundles the options to create a GaugeVec metric.
|
||||
// It is mandatory to set GaugeOpts, see there for mandatory fields. VariableLabels
|
||||
// is optional and can safely be left to its default value.
|
||||
type GaugeVecOpts struct {
|
||||
GaugeOpts
|
||||
|
||||
// VariableLabels are used to partition the metric vector by the given set
|
||||
// of labels. Each label value will be constrained with the optional Constraint
|
||||
// function, if provided.
|
||||
VariableLabels ConstrainableLabels
|
||||
}
|
||||
|
||||
// NewGauge creates a new Gauge based on the provided GaugeOpts.
|
||||
//
|
||||
// The returned implementation is optimized for a fast Set method. If you have a
|
||||
|
|
@ -123,7 +135,7 @@ func (g *gauge) Sub(val float64) {
|
|||
|
||||
func (g *gauge) Write(out *dto.Metric) error {
|
||||
val := math.Float64frombits(atomic.LoadUint64(&g.valBits))
|
||||
return populateMetric(GaugeValue, val, g.labelPairs, nil, out)
|
||||
return populateMetric(GaugeValue, val, g.labelPairs, nil, out, nil)
|
||||
}
|
||||
|
||||
// GaugeVec is a Collector that bundles a set of Gauges that all share the same
|
||||
|
|
@ -138,16 +150,24 @@ type GaugeVec struct {
|
|||
// NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
|
||||
// partitioned by the given label names.
|
||||
func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
|
||||
desc := NewDesc(
|
||||
return V2.NewGaugeVec(GaugeVecOpts{
|
||||
GaugeOpts: opts,
|
||||
VariableLabels: UnconstrainedLabels(labelNames),
|
||||
})
|
||||
}
|
||||
|
||||
// NewGaugeVec creates a new GaugeVec based on the provided GaugeVecOpts.
|
||||
func (v2) NewGaugeVec(opts GaugeVecOpts) *GaugeVec {
|
||||
desc := V2.NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
labelNames,
|
||||
opts.VariableLabels,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
return &GaugeVec{
|
||||
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
|
||||
if len(lvs) != len(desc.variableLabels) {
|
||||
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
|
||||
if len(lvs) != len(desc.variableLabels.names) {
|
||||
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels.names, lvs))
|
||||
}
|
||||
result := &gauge{desc: desc, labelPairs: MakeLabelPairs(desc, lvs)}
|
||||
result.init(result) // Init self-collection.
|
||||
|
|
|
|||
|
|
@ -23,11 +23,10 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/internal"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// nativeHistogramBounds for the frac of observed values. Only relevant for
|
||||
|
|
@ -392,7 +392,7 @@ type HistogramOpts struct {
|
|||
// zero, it is replaced by default buckets. The default buckets are
|
||||
// DefBuckets if no buckets for a native histogram (see below) are used,
|
||||
// otherwise the default is no buckets. (In other words, if you want to
|
||||
// use both reguler buckets and buckets for a native histogram, you have
|
||||
// use both regular buckets and buckets for a native histogram, you have
|
||||
// to define the regular buckets here explicitly.)
|
||||
Buckets []float64
|
||||
|
||||
|
|
@ -402,7 +402,7 @@ type HistogramOpts struct {
|
|||
// Histogram by a Prometheus server with that feature enabled (requires
|
||||
// Prometheus v2.40+). Sparse buckets are exponential buckets covering
|
||||
// the whole float64 range (with the exception of the “zero” bucket, see
|
||||
// SparseBucketsZeroThreshold below). From any one bucket to the next,
|
||||
// NativeHistogramZeroThreshold below). From any one bucket to the next,
|
||||
// the width of the bucket grows by a constant
|
||||
// factor. NativeHistogramBucketFactor provides an upper bound for this
|
||||
// factor (exception see below). The smaller
|
||||
|
|
@ -414,8 +414,8 @@ type HistogramOpts struct {
|
|||
// and 2, same as between 2 and 4, and 4 and 8, etc.).
|
||||
//
|
||||
// Details about the actually used factor: The factor is calculated as
|
||||
// 2^(2^n), where n is an integer number between (and including) -8 and
|
||||
// 4. n is chosen so that the resulting factor is the largest that is
|
||||
// 2^(2^-n), where n is an integer number between (and including) -4 and
|
||||
// 8. n is chosen so that the resulting factor is the largest that is
|
||||
// still smaller or equal to NativeHistogramBucketFactor. Note that the
|
||||
// smallest possible factor is therefore approx. 1.00271 (i.e. 2^(2^-8)
|
||||
// ). If NativeHistogramBucketFactor is greater than 1 but smaller than
|
||||
|
|
@ -429,12 +429,12 @@ type HistogramOpts struct {
|
|||
// a major version bump.
|
||||
NativeHistogramBucketFactor float64
|
||||
// All observations with an absolute value of less or equal
|
||||
// NativeHistogramZeroThreshold are accumulated into a “zero”
|
||||
// bucket. For best results, this should be close to a bucket
|
||||
// boundary. This is usually the case if picking a power of two. If
|
||||
// NativeHistogramZeroThreshold are accumulated into a “zero” bucket.
|
||||
// For best results, this should be close to a bucket boundary. This is
|
||||
// usually the case if picking a power of two. If
|
||||
// NativeHistogramZeroThreshold is left at zero,
|
||||
// DefSparseBucketsZeroThreshold is used as the threshold. To configure
|
||||
// a zero bucket with an actual threshold of zero (i.e. only
|
||||
// DefNativeHistogramZeroThreshold is used as the threshold. To
|
||||
// configure a zero bucket with an actual threshold of zero (i.e. only
|
||||
// observations of precisely zero will go into the zero bucket), set
|
||||
// NativeHistogramZeroThreshold to the NativeHistogramZeroThresholdZero
|
||||
// constant (or any negative float value).
|
||||
|
|
@ -447,26 +447,46 @@ type HistogramOpts struct {
|
|||
// Histogram are sufficiently wide-spread. In particular, this could be
|
||||
// used as a DoS attack vector. Where the observed values depend on
|
||||
// external inputs, it is highly recommended to set a
|
||||
// NativeHistogramMaxBucketNumber.) Once the set
|
||||
// NativeHistogramMaxBucketNumber.) Once the set
|
||||
// NativeHistogramMaxBucketNumber is exceeded, the following strategy is
|
||||
// enacted: First, if the last reset (or the creation) of the histogram
|
||||
// is at least NativeHistogramMinResetDuration ago, then the whole
|
||||
// histogram is reset to its initial state (including regular
|
||||
// buckets). If less time has passed, or if
|
||||
// NativeHistogramMinResetDuration is zero, no reset is
|
||||
// performed. Instead, the zero threshold is increased sufficiently to
|
||||
// reduce the number of buckets to or below
|
||||
// NativeHistogramMaxBucketNumber, but not to more than
|
||||
// NativeHistogramMaxZeroThreshold. Thus, if
|
||||
// NativeHistogramMaxZeroThreshold is already at or below the current
|
||||
// zero threshold, nothing happens at this step. After that, if the
|
||||
// number of buckets still exceeds NativeHistogramMaxBucketNumber, the
|
||||
// resolution of the histogram is reduced by doubling the width of the
|
||||
// sparse buckets (up to a growth factor between one bucket to the next
|
||||
// of 2^(2^4) = 65536, see above).
|
||||
// enacted:
|
||||
// - First, if the last reset (or the creation) of the histogram is at
|
||||
// least NativeHistogramMinResetDuration ago, then the whole
|
||||
// histogram is reset to its initial state (including regular
|
||||
// buckets).
|
||||
// - If less time has passed, or if NativeHistogramMinResetDuration is
|
||||
// zero, no reset is performed. Instead, the zero threshold is
|
||||
// increased sufficiently to reduce the number of buckets to or below
|
||||
// NativeHistogramMaxBucketNumber, but not to more than
|
||||
// NativeHistogramMaxZeroThreshold. Thus, if
|
||||
// NativeHistogramMaxZeroThreshold is already at or below the current
|
||||
// zero threshold, nothing happens at this step.
|
||||
// - After that, if the number of buckets still exceeds
|
||||
// NativeHistogramMaxBucketNumber, the resolution of the histogram is
|
||||
// reduced by doubling the width of the sparse buckets (up to a
|
||||
// growth factor between one bucket to the next of 2^(2^4) = 65536,
|
||||
// see above).
|
||||
// - Any increased zero threshold or reduced resolution is reset back
|
||||
// to their original values once NativeHistogramMinResetDuration has
|
||||
// passed (since the last reset or the creation of the histogram).
|
||||
NativeHistogramMaxBucketNumber uint32
|
||||
NativeHistogramMinResetDuration time.Duration
|
||||
NativeHistogramMaxZeroThreshold float64
|
||||
|
||||
// now is for testing purposes, by default it's time.Now.
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
// HistogramVecOpts bundles the options to create a HistogramVec metric.
|
||||
// It is mandatory to set HistogramOpts, see there for mandatory fields. VariableLabels
|
||||
// is optional and can safely be left to its default value.
|
||||
type HistogramVecOpts struct {
|
||||
HistogramOpts
|
||||
|
||||
// VariableLabels are used to partition the metric vector by the given set
|
||||
// of labels. Each label value will be constrained with the optional Constraint
|
||||
// function, if provided.
|
||||
VariableLabels ConstrainableLabels
|
||||
}
|
||||
|
||||
// NewHistogram creates a new Histogram based on the provided HistogramOpts. It
|
||||
|
|
@ -488,11 +508,11 @@ func NewHistogram(opts HistogramOpts) Histogram {
|
|||
}
|
||||
|
||||
func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogram {
|
||||
if len(desc.variableLabels) != len(labelValues) {
|
||||
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues))
|
||||
if len(desc.variableLabels.names) != len(labelValues) {
|
||||
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels.names, labelValues))
|
||||
}
|
||||
|
||||
for _, n := range desc.variableLabels {
|
||||
for _, n := range desc.variableLabels.names {
|
||||
if n == bucketLabel {
|
||||
panic(errBucketLabelNotAllowed)
|
||||
}
|
||||
|
|
@ -503,6 +523,10 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
|||
}
|
||||
}
|
||||
|
||||
if opts.now == nil {
|
||||
opts.now = time.Now
|
||||
}
|
||||
|
||||
h := &histogram{
|
||||
desc: desc,
|
||||
upperBounds: opts.Buckets,
|
||||
|
|
@ -510,8 +534,8 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
|||
nativeHistogramMaxBuckets: opts.NativeHistogramMaxBucketNumber,
|
||||
nativeHistogramMaxZeroThreshold: opts.NativeHistogramMaxZeroThreshold,
|
||||
nativeHistogramMinResetDuration: opts.NativeHistogramMinResetDuration,
|
||||
lastResetTime: time.Now(),
|
||||
now: time.Now,
|
||||
lastResetTime: opts.now(),
|
||||
now: opts.now,
|
||||
}
|
||||
if len(h.upperBounds) == 0 && opts.NativeHistogramBucketFactor <= 1 {
|
||||
h.upperBounds = DefBuckets
|
||||
|
|
@ -544,16 +568,12 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
|||
}
|
||||
// Finally we know the final length of h.upperBounds and can make buckets
|
||||
// for both counts as well as exemplars:
|
||||
h.counts[0] = &histogramCounts{
|
||||
buckets: make([]uint64, len(h.upperBounds)),
|
||||
nativeHistogramZeroThresholdBits: math.Float64bits(h.nativeHistogramZeroThreshold),
|
||||
nativeHistogramSchema: h.nativeHistogramSchema,
|
||||
}
|
||||
h.counts[1] = &histogramCounts{
|
||||
buckets: make([]uint64, len(h.upperBounds)),
|
||||
nativeHistogramZeroThresholdBits: math.Float64bits(h.nativeHistogramZeroThreshold),
|
||||
nativeHistogramSchema: h.nativeHistogramSchema,
|
||||
}
|
||||
h.counts[0] = &histogramCounts{buckets: make([]uint64, len(h.upperBounds))}
|
||||
atomic.StoreUint64(&h.counts[0].nativeHistogramZeroThresholdBits, math.Float64bits(h.nativeHistogramZeroThreshold))
|
||||
atomic.StoreInt32(&h.counts[0].nativeHistogramSchema, h.nativeHistogramSchema)
|
||||
h.counts[1] = &histogramCounts{buckets: make([]uint64, len(h.upperBounds))}
|
||||
atomic.StoreUint64(&h.counts[1].nativeHistogramZeroThresholdBits, math.Float64bits(h.nativeHistogramZeroThreshold))
|
||||
atomic.StoreInt32(&h.counts[1].nativeHistogramSchema, h.nativeHistogramSchema)
|
||||
h.exemplars = make([]atomic.Value, len(h.upperBounds)+1)
|
||||
|
||||
h.init(h) // Init self-collection.
|
||||
|
|
@ -632,8 +652,8 @@ func (hc *histogramCounts) observe(v float64, bucket int, doSparse bool) {
|
|||
if frac == 0.5 {
|
||||
key--
|
||||
}
|
||||
div := 1 << -schema
|
||||
key = (key + div - 1) / div
|
||||
offset := (1 << -schema) - 1
|
||||
key = (key + offset) >> -schema
|
||||
}
|
||||
if isInf {
|
||||
key++
|
||||
|
|
@ -694,9 +714,11 @@ type histogram struct {
|
|||
nativeHistogramMaxZeroThreshold float64
|
||||
nativeHistogramMaxBuckets uint32
|
||||
nativeHistogramMinResetDuration time.Duration
|
||||
lastResetTime time.Time // Protected by mtx.
|
||||
// lastResetTime is protected by mtx. It is also used as created timestamp.
|
||||
lastResetTime time.Time
|
||||
|
||||
now func() time.Time // To mock out time.Now() for testing.
|
||||
// now is for testing purposes, by default it's time.Now.
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
func (h *histogram) Desc() *Desc {
|
||||
|
|
@ -735,9 +757,10 @@ func (h *histogram) Write(out *dto.Metric) error {
|
|||
waitForCooldown(count, coldCounts)
|
||||
|
||||
his := &dto.Histogram{
|
||||
Bucket: make([]*dto.Bucket, len(h.upperBounds)),
|
||||
SampleCount: proto.Uint64(count),
|
||||
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
|
||||
Bucket: make([]*dto.Bucket, len(h.upperBounds)),
|
||||
SampleCount: proto.Uint64(count),
|
||||
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
|
||||
CreatedTimestamp: timestamppb.New(h.lastResetTime),
|
||||
}
|
||||
out.Histogram = his
|
||||
out.Label = h.labelPairs
|
||||
|
|
@ -775,6 +798,16 @@ func (h *histogram) Write(out *dto.Metric) error {
|
|||
his.ZeroCount = proto.Uint64(zeroBucket)
|
||||
his.NegativeSpan, his.NegativeDelta = makeBuckets(&coldCounts.nativeHistogramBucketsNegative)
|
||||
his.PositiveSpan, his.PositiveDelta = makeBuckets(&coldCounts.nativeHistogramBucketsPositive)
|
||||
|
||||
// Add a no-op span to a histogram without observations and with
|
||||
// a zero threshold of zero. Otherwise, a native histogram would
|
||||
// look like a classic histogram to scrapers.
|
||||
if *his.ZeroThreshold == 0 && *his.ZeroCount == 0 && len(his.PositiveSpan) == 0 && len(his.NegativeSpan) == 0 {
|
||||
his.PositiveSpan = []*dto.BucketSpan{{
|
||||
Offset: proto.Int32(0),
|
||||
Length: proto.Uint32(0),
|
||||
}}
|
||||
}
|
||||
}
|
||||
addAndResetCounts(hotCounts, coldCounts)
|
||||
return nil
|
||||
|
|
@ -810,7 +843,7 @@ func (h *histogram) observe(v float64, bucket int) {
|
|||
}
|
||||
}
|
||||
|
||||
// limitSparsebuckets applies a strategy to limit the number of populated sparse
|
||||
// limitBuckets applies a strategy to limit the number of populated sparse
|
||||
// buckets. It's generally best effort, and there are situations where the
|
||||
// number can go higher (if even the lowest resolution isn't enough to reduce
|
||||
// the number sufficiently, or if the provided counts aren't fully updated yet
|
||||
|
|
@ -847,20 +880,23 @@ func (h *histogram) limitBuckets(counts *histogramCounts, value float64, bucket
|
|||
h.doubleBucketWidth(hotCounts, coldCounts)
|
||||
}
|
||||
|
||||
// maybeReset resests the whole histogram if at least h.nativeHistogramMinResetDuration
|
||||
// maybeReset resets the whole histogram if at least h.nativeHistogramMinResetDuration
|
||||
// has been passed. It returns true if the histogram has been reset. The caller
|
||||
// must have locked h.mtx.
|
||||
func (h *histogram) maybeReset(hot, cold *histogramCounts, coldIdx uint64, value float64, bucket int) bool {
|
||||
func (h *histogram) maybeReset(
|
||||
hot, cold *histogramCounts, coldIdx uint64, value float64, bucket int,
|
||||
) bool {
|
||||
// We are using the possibly mocked h.now() rather than
|
||||
// time.Since(h.lastResetTime) to enable testing.
|
||||
if h.nativeHistogramMinResetDuration == 0 || h.now().Sub(h.lastResetTime) < h.nativeHistogramMinResetDuration {
|
||||
if h.nativeHistogramMinResetDuration == 0 ||
|
||||
h.now().Sub(h.lastResetTime) < h.nativeHistogramMinResetDuration {
|
||||
return false
|
||||
}
|
||||
// Completely reset coldCounts.
|
||||
h.resetCounts(cold)
|
||||
// Repeat the latest observation to not lose it completely.
|
||||
cold.observe(value, bucket, true)
|
||||
// Make coldCounts the new hot counts while ressetting countAndHotIdx.
|
||||
// Make coldCounts the new hot counts while resetting countAndHotIdx.
|
||||
n := atomic.SwapUint64(&h.countAndHotIdx, (coldIdx<<63)+1)
|
||||
count := n & ((1 << 63) - 1)
|
||||
waitForCooldown(count, hot)
|
||||
|
|
@ -1034,15 +1070,23 @@ type HistogramVec struct {
|
|||
// NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and
|
||||
// partitioned by the given label names.
|
||||
func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
|
||||
desc := NewDesc(
|
||||
return V2.NewHistogramVec(HistogramVecOpts{
|
||||
HistogramOpts: opts,
|
||||
VariableLabels: UnconstrainedLabels(labelNames),
|
||||
})
|
||||
}
|
||||
|
||||
// NewHistogramVec creates a new HistogramVec based on the provided HistogramVecOpts.
|
||||
func (v2) NewHistogramVec(opts HistogramVecOpts) *HistogramVec {
|
||||
desc := V2.NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
labelNames,
|
||||
opts.VariableLabels,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
return &HistogramVec{
|
||||
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
|
||||
return newHistogram(desc, opts, lvs...)
|
||||
return newHistogram(desc, opts.HistogramOpts, lvs...)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
@ -1161,6 +1205,7 @@ type constHistogram struct {
|
|||
sum float64
|
||||
buckets map[float64]uint64
|
||||
labelPairs []*dto.LabelPair
|
||||
createdTs *timestamppb.Timestamp
|
||||
}
|
||||
|
||||
func (h *constHistogram) Desc() *Desc {
|
||||
|
|
@ -1168,7 +1213,9 @@ func (h *constHistogram) Desc() *Desc {
|
|||
}
|
||||
|
||||
func (h *constHistogram) Write(out *dto.Metric) error {
|
||||
his := &dto.Histogram{}
|
||||
his := &dto.Histogram{
|
||||
CreatedTimestamp: h.createdTs,
|
||||
}
|
||||
|
||||
buckets := make([]*dto.Bucket, 0, len(h.buckets))
|
||||
|
||||
|
|
@ -1215,7 +1262,7 @@ func NewConstHistogram(
|
|||
if desc.err != nil {
|
||||
return nil, desc.err
|
||||
}
|
||||
if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
|
||||
if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &constHistogram{
|
||||
|
|
@ -1309,7 +1356,7 @@ func makeBuckets(buckets *sync.Map) ([]*dto.BucketSpan, []int64) {
|
|||
// Multiple spans with only small gaps in between are probably
|
||||
// encoded more efficiently as one larger span with a few empty
|
||||
// buckets. Needs some research to find the sweet spot. For now,
|
||||
// we assume that gaps of one ore two buckets should not create
|
||||
// we assume that gaps of one or two buckets should not create
|
||||
// a new span.
|
||||
iDelta := int32(i - nextI)
|
||||
if n == 0 || iDelta > 2 {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
// It provides tools to compare sequences of strings and generate textual diffs.
|
||||
//
|
||||
// Maintaining `GetUnifiedDiffString` here because original repository
|
||||
// (https://github.com/pmezard/go-difflib) is no loger maintained.
|
||||
// (https://github.com/pmezard/go-difflib) is no longer maintained.
|
||||
package internal
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -32,6 +32,104 @@ import (
|
|||
// create a Desc.
|
||||
type Labels map[string]string
|
||||
|
||||
// LabelConstraint normalizes label values.
|
||||
type LabelConstraint func(string) string
|
||||
|
||||
// ConstrainedLabels represents a label name and its constrain function
|
||||
// to normalize label values. This type is commonly used when constructing
|
||||
// metric vector Collectors.
|
||||
type ConstrainedLabel struct {
|
||||
Name string
|
||||
Constraint LabelConstraint
|
||||
}
|
||||
|
||||
// ConstrainableLabels is an interface that allows creating of labels that can
|
||||
// be optionally constrained.
|
||||
//
|
||||
// prometheus.V2().NewCounterVec(CounterVecOpts{
|
||||
// CounterOpts: {...}, // Usual CounterOpts fields
|
||||
// VariableLabels: []ConstrainedLabels{
|
||||
// {Name: "A"},
|
||||
// {Name: "B", Constraint: func(v string) string { ... }},
|
||||
// },
|
||||
// })
|
||||
type ConstrainableLabels interface {
|
||||
compile() *compiledLabels
|
||||
labelNames() []string
|
||||
}
|
||||
|
||||
// ConstrainedLabels represents a collection of label name -> constrain function
|
||||
// to normalize label values. This type is commonly used when constructing
|
||||
// metric vector Collectors.
|
||||
type ConstrainedLabels []ConstrainedLabel
|
||||
|
||||
func (cls ConstrainedLabels) compile() *compiledLabels {
|
||||
compiled := &compiledLabels{
|
||||
names: make([]string, len(cls)),
|
||||
labelConstraints: map[string]LabelConstraint{},
|
||||
}
|
||||
|
||||
for i, label := range cls {
|
||||
compiled.names[i] = label.Name
|
||||
if label.Constraint != nil {
|
||||
compiled.labelConstraints[label.Name] = label.Constraint
|
||||
}
|
||||
}
|
||||
|
||||
return compiled
|
||||
}
|
||||
|
||||
func (cls ConstrainedLabels) labelNames() []string {
|
||||
names := make([]string, len(cls))
|
||||
for i, label := range cls {
|
||||
names[i] = label.Name
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// UnconstrainedLabels represents collection of label without any constraint on
|
||||
// their value. Thus, it is simply a collection of label names.
|
||||
//
|
||||
// UnconstrainedLabels([]string{ "A", "B" })
|
||||
//
|
||||
// is equivalent to
|
||||
//
|
||||
// ConstrainedLabels {
|
||||
// { Name: "A" },
|
||||
// { Name: "B" },
|
||||
// }
|
||||
type UnconstrainedLabels []string
|
||||
|
||||
func (uls UnconstrainedLabels) compile() *compiledLabels {
|
||||
return &compiledLabels{
|
||||
names: uls,
|
||||
}
|
||||
}
|
||||
|
||||
func (uls UnconstrainedLabels) labelNames() []string {
|
||||
return uls
|
||||
}
|
||||
|
||||
type compiledLabels struct {
|
||||
names []string
|
||||
labelConstraints map[string]LabelConstraint
|
||||
}
|
||||
|
||||
func (cls *compiledLabels) compile() *compiledLabels {
|
||||
return cls
|
||||
}
|
||||
|
||||
func (cls *compiledLabels) labelNames() []string {
|
||||
return cls.names
|
||||
}
|
||||
|
||||
func (cls *compiledLabels) constrain(labelName, value string) string {
|
||||
if fn, ok := cls.labelConstraints[labelName]; ok && fn != nil {
|
||||
return fn(value)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// reservedLabelPrefix is a prefix which is not legal in user-supplied
|
||||
// label names.
|
||||
const reservedLabelPrefix = "__"
|
||||
|
|
|
|||
|
|
@ -20,11 +20,9 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"github.com/prometheus/common/model"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var separatorByteSlice = []byte{model.SeparatorByte} // For convenient use with xxhash.
|
||||
|
|
@ -94,6 +92,9 @@ type Opts struct {
|
|||
// machine_role metric). See also
|
||||
// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels
|
||||
ConstLabels Labels
|
||||
|
||||
// now is for testing purposes, by default it's time.Now.
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
// BuildFQName joins the given three name components by "_". Empty name
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -47,9 +48,10 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
contentTypeHeader = "Content-Type"
|
||||
contentEncodingHeader = "Content-Encoding"
|
||||
acceptEncodingHeader = "Accept-Encoding"
|
||||
contentTypeHeader = "Content-Type"
|
||||
contentEncodingHeader = "Content-Encoding"
|
||||
acceptEncodingHeader = "Accept-Encoding"
|
||||
processStartTimeHeader = "Process-Start-Time-Unix"
|
||||
)
|
||||
|
||||
var gzipPool = sync.Pool{
|
||||
|
|
@ -121,6 +123,9 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO
|
|||
}
|
||||
|
||||
h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) {
|
||||
if !opts.ProcessStartTime.IsZero() {
|
||||
rsp.Header().Set(processStartTimeHeader, strconv.FormatInt(opts.ProcessStartTime.Unix(), 10))
|
||||
}
|
||||
if inFlightSem != nil {
|
||||
select {
|
||||
case inFlightSem <- struct{}{}: // All good, carry on.
|
||||
|
|
@ -366,6 +371,14 @@ type HandlerOpts struct {
|
|||
// (which changes the identity of the resulting series on the Prometheus
|
||||
// server).
|
||||
EnableOpenMetrics bool
|
||||
// ProcessStartTime allows setting process start timevalue that will be exposed
|
||||
// with "Process-Start-Time-Unix" response header along with the metrics
|
||||
// payload. This allow callers to have efficient transformations to cumulative
|
||||
// counters (e.g. OpenTelemetry) or generally _created timestamp estimation per
|
||||
// scrape target.
|
||||
// NOTE: This feature is experimental and not covered by OpenMetrics or Prometheus
|
||||
// exposition format.
|
||||
ProcessStartTime time.Time
|
||||
}
|
||||
|
||||
// gzipAccepted returns whether the client will accept gzip-encoded content.
|
||||
|
|
|
|||
26
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
generated
vendored
26
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
generated
vendored
|
|
@ -68,16 +68,17 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
|
|||
o.apply(rtOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(counter)
|
||||
// Curry the counter with dynamic labels before checking the remaining labels.
|
||||
code, method := checkLabels(counter.MustCurryWith(rtOpts.emptyDynamicLabels()))
|
||||
|
||||
return func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := next.RoundTrip(r)
|
||||
if err == nil {
|
||||
addWithExemplar(
|
||||
counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)),
|
||||
1,
|
||||
rtOpts.getExemplarFn(r.Context()),
|
||||
)
|
||||
l := labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)
|
||||
for label, resolve := range rtOpts.extraLabelsFromCtx {
|
||||
l[label] = resolve(resp.Request.Context())
|
||||
}
|
||||
addWithExemplar(counter.With(l), 1, rtOpts.getExemplarFn(r.Context()))
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
|
@ -110,17 +111,18 @@ func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundT
|
|||
o.apply(rtOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(obs)
|
||||
// Curry the observer with dynamic labels before checking the remaining labels.
|
||||
code, method := checkLabels(obs.MustCurryWith(rtOpts.emptyDynamicLabels()))
|
||||
|
||||
return func(r *http.Request) (*http.Response, error) {
|
||||
start := time.Now()
|
||||
resp, err := next.RoundTrip(r)
|
||||
if err == nil {
|
||||
observeWithExemplar(
|
||||
obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)),
|
||||
time.Since(start).Seconds(),
|
||||
rtOpts.getExemplarFn(r.Context()),
|
||||
)
|
||||
l := labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)
|
||||
for label, resolve := range rtOpts.extraLabelsFromCtx {
|
||||
l[label] = resolve(resp.Request.Context())
|
||||
}
|
||||
observeWithExemplar(obs.With(l), time.Since(start).Seconds(), rtOpts.getExemplarFn(r.Context()))
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
|
|
|||
112
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
generated
vendored
112
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
generated
vendored
|
|
@ -87,7 +87,8 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, op
|
|||
o.apply(hOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(obs)
|
||||
// Curry the observer with dynamic labels before checking the remaining labels.
|
||||
code, method := checkLabels(obs.MustCurryWith(hOpts.emptyDynamicLabels()))
|
||||
|
||||
if code {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -95,23 +96,22 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, op
|
|||
d := newDelegator(w, nil)
|
||||
next.ServeHTTP(d, r)
|
||||
|
||||
observeWithExemplar(
|
||||
obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
|
||||
time.Since(now).Seconds(),
|
||||
hOpts.getExemplarFn(r.Context()),
|
||||
)
|
||||
l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)
|
||||
for label, resolve := range hOpts.extraLabelsFromCtx {
|
||||
l[label] = resolve(r.Context())
|
||||
}
|
||||
observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
|
||||
}
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
now := time.Now()
|
||||
next.ServeHTTP(w, r)
|
||||
|
||||
observeWithExemplar(
|
||||
obs.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)),
|
||||
time.Since(now).Seconds(),
|
||||
hOpts.getExemplarFn(r.Context()),
|
||||
)
|
||||
l := labels(code, method, r.Method, 0, hOpts.extraMethods...)
|
||||
for label, resolve := range hOpts.extraLabelsFromCtx {
|
||||
l[label] = resolve(r.Context())
|
||||
}
|
||||
observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -138,28 +138,30 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler,
|
|||
o.apply(hOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(counter)
|
||||
// Curry the counter with dynamic labels before checking the remaining labels.
|
||||
code, method := checkLabels(counter.MustCurryWith(hOpts.emptyDynamicLabels()))
|
||||
|
||||
if code {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
d := newDelegator(w, nil)
|
||||
next.ServeHTTP(d, r)
|
||||
|
||||
addWithExemplar(
|
||||
counter.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
|
||||
1,
|
||||
hOpts.getExemplarFn(r.Context()),
|
||||
)
|
||||
l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)
|
||||
for label, resolve := range hOpts.extraLabelsFromCtx {
|
||||
l[label] = resolve(r.Context())
|
||||
}
|
||||
addWithExemplar(counter.With(l), 1, hOpts.getExemplarFn(r.Context()))
|
||||
}
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
next.ServeHTTP(w, r)
|
||||
addWithExemplar(
|
||||
counter.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)),
|
||||
1,
|
||||
hOpts.getExemplarFn(r.Context()),
|
||||
)
|
||||
|
||||
l := labels(code, method, r.Method, 0, hOpts.extraMethods...)
|
||||
for label, resolve := range hOpts.extraLabelsFromCtx {
|
||||
l[label] = resolve(r.Context())
|
||||
}
|
||||
addWithExemplar(counter.With(l), 1, hOpts.getExemplarFn(r.Context()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,16 +193,17 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
|
|||
o.apply(hOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(obs)
|
||||
// Curry the observer with dynamic labels before checking the remaining labels.
|
||||
code, method := checkLabels(obs.MustCurryWith(hOpts.emptyDynamicLabels()))
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
now := time.Now()
|
||||
d := newDelegator(w, func(status int) {
|
||||
observeWithExemplar(
|
||||
obs.With(labels(code, method, r.Method, status, hOpts.extraMethods...)),
|
||||
time.Since(now).Seconds(),
|
||||
hOpts.getExemplarFn(r.Context()),
|
||||
)
|
||||
l := labels(code, method, r.Method, status, hOpts.extraMethods...)
|
||||
for label, resolve := range hOpts.extraLabelsFromCtx {
|
||||
l[label] = resolve(r.Context())
|
||||
}
|
||||
observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context()))
|
||||
})
|
||||
next.ServeHTTP(d, r)
|
||||
}
|
||||
|
|
@ -231,28 +234,32 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler,
|
|||
o.apply(hOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(obs)
|
||||
// Curry the observer with dynamic labels before checking the remaining labels.
|
||||
code, method := checkLabels(obs.MustCurryWith(hOpts.emptyDynamicLabels()))
|
||||
|
||||
if code {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
d := newDelegator(w, nil)
|
||||
next.ServeHTTP(d, r)
|
||||
size := computeApproximateRequestSize(r)
|
||||
observeWithExemplar(
|
||||
obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
|
||||
float64(size),
|
||||
hOpts.getExemplarFn(r.Context()),
|
||||
)
|
||||
|
||||
l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)
|
||||
for label, resolve := range hOpts.extraLabelsFromCtx {
|
||||
l[label] = resolve(r.Context())
|
||||
}
|
||||
observeWithExemplar(obs.With(l), float64(size), hOpts.getExemplarFn(r.Context()))
|
||||
}
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
next.ServeHTTP(w, r)
|
||||
size := computeApproximateRequestSize(r)
|
||||
observeWithExemplar(
|
||||
obs.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)),
|
||||
float64(size),
|
||||
hOpts.getExemplarFn(r.Context()),
|
||||
)
|
||||
|
||||
l := labels(code, method, r.Method, 0, hOpts.extraMethods...)
|
||||
for label, resolve := range hOpts.extraLabelsFromCtx {
|
||||
l[label] = resolve(r.Context())
|
||||
}
|
||||
observeWithExemplar(obs.With(l), float64(size), hOpts.getExemplarFn(r.Context()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -281,16 +288,18 @@ func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler
|
|||
o.apply(hOpts)
|
||||
}
|
||||
|
||||
code, method := checkLabels(obs)
|
||||
// Curry the observer with dynamic labels before checking the remaining labels.
|
||||
code, method := checkLabels(obs.MustCurryWith(hOpts.emptyDynamicLabels()))
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
d := newDelegator(w, nil)
|
||||
next.ServeHTTP(d, r)
|
||||
observeWithExemplar(
|
||||
obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
|
||||
float64(d.Written()),
|
||||
hOpts.getExemplarFn(r.Context()),
|
||||
)
|
||||
|
||||
l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)
|
||||
for label, resolve := range hOpts.extraLabelsFromCtx {
|
||||
l[label] = resolve(r.Context())
|
||||
}
|
||||
observeWithExemplar(obs.With(l), float64(d.Written()), hOpts.getExemplarFn(r.Context()))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -380,16 +389,13 @@ func isLabelCurried(c prometheus.Collector, label string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// emptyLabels is a one-time allocation for non-partitioned metrics to avoid
|
||||
// unnecessary allocations on each request.
|
||||
var emptyLabels = prometheus.Labels{}
|
||||
|
||||
func labels(code, method bool, reqMethod string, status int, extraMethods ...string) prometheus.Labels {
|
||||
if !(code || method) {
|
||||
return emptyLabels
|
||||
}
|
||||
labels := prometheus.Labels{}
|
||||
|
||||
if !(code || method) {
|
||||
return labels
|
||||
}
|
||||
|
||||
if code {
|
||||
labels["code"] = sanitizeCode(status)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,14 +24,32 @@ type Option interface {
|
|||
apply(*options)
|
||||
}
|
||||
|
||||
// LabelValueFromCtx are used to compute the label value from request context.
|
||||
// Context can be filled with values from request through middleware.
|
||||
type LabelValueFromCtx func(ctx context.Context) string
|
||||
|
||||
// options store options for both a handler or round tripper.
|
||||
type options struct {
|
||||
extraMethods []string
|
||||
getExemplarFn func(requestCtx context.Context) prometheus.Labels
|
||||
extraMethods []string
|
||||
getExemplarFn func(requestCtx context.Context) prometheus.Labels
|
||||
extraLabelsFromCtx map[string]LabelValueFromCtx
|
||||
}
|
||||
|
||||
func defaultOptions() *options {
|
||||
return &options{getExemplarFn: func(ctx context.Context) prometheus.Labels { return nil }}
|
||||
return &options{
|
||||
getExemplarFn: func(ctx context.Context) prometheus.Labels { return nil },
|
||||
extraLabelsFromCtx: map[string]LabelValueFromCtx{},
|
||||
}
|
||||
}
|
||||
|
||||
func (o *options) emptyDynamicLabels() prometheus.Labels {
|
||||
labels := prometheus.Labels{}
|
||||
|
||||
for label := range o.extraLabelsFromCtx {
|
||||
labels[label] = ""
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
type optionApplyFunc func(*options)
|
||||
|
|
@ -48,11 +66,19 @@ func WithExtraMethods(methods ...string) Option {
|
|||
})
|
||||
}
|
||||
|
||||
// WithExemplarFromContext adds allows to put a hook to all counter and histogram metrics.
|
||||
// If the hook function returns non-nil labels, exemplars will be added for that request, otherwise metric
|
||||
// will get instrumented without exemplar.
|
||||
// WithExemplarFromContext allows to inject function that will get exemplar from context that will be put to counter and histogram metrics.
|
||||
// If the function returns nil labels or the metric does not support exemplars, no exemplar will be added (noop), but
|
||||
// metric will continue to observe/increment.
|
||||
func WithExemplarFromContext(getExemplarFn func(requestCtx context.Context) prometheus.Labels) Option {
|
||||
return optionApplyFunc(func(o *options) {
|
||||
o.getExemplarFn = getExemplarFn
|
||||
})
|
||||
}
|
||||
|
||||
// WithLabelFromCtx registers a label for dynamic resolution with access to context.
|
||||
// See the example for ExampleInstrumentHandlerWithLabelResolver for example usage
|
||||
func WithLabelFromCtx(name string, valueFn LabelValueFromCtx) Option {
|
||||
return optionApplyFunc(func(o *options) {
|
||||
o.extraLabelsFromCtx[name] = valueFn
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,18 +21,17 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/cespare/xxhash/v2"
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/prometheus/common/expfmt"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/internal"
|
||||
|
||||
"github.com/cespare/xxhash/v2"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"github.com/prometheus/common/expfmt"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -549,7 +548,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
|
|||
goroutineBudget--
|
||||
runtime.Gosched()
|
||||
}
|
||||
// Once both checkedMetricChan and uncheckdMetricChan are closed
|
||||
// Once both checkedMetricChan and uncheckedMetricChan are closed
|
||||
// and drained, the contraption above will nil out cmc and umc,
|
||||
// and then we can leave the collect loop here.
|
||||
if cmc == nil && umc == nil {
|
||||
|
|
@ -933,6 +932,10 @@ func checkMetricConsistency(
|
|||
h.WriteString(lp.GetValue())
|
||||
h.Write(separatorByteSlice)
|
||||
}
|
||||
if dtoMetric.TimestampMs != nil {
|
||||
h.WriteString(strconv.FormatInt(*(dtoMetric.TimestampMs), 10))
|
||||
h.Write(separatorByteSlice)
|
||||
}
|
||||
hSum := h.Sum64()
|
||||
if _, exists := metricHashes[hSum]; exists {
|
||||
return fmt.Errorf(
|
||||
|
|
@ -960,7 +963,7 @@ func checkDescConsistency(
|
|||
// Is the desc consistent with the content of the metric?
|
||||
lpsFromDesc := make([]*dto.LabelPair, len(desc.constLabelPairs), len(dtoMetric.Label))
|
||||
copy(lpsFromDesc, desc.constLabelPairs)
|
||||
for _, l := range desc.variableLabels {
|
||||
for _, l := range desc.variableLabels.names {
|
||||
lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{
|
||||
Name: proto.String(l),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/beorn7/perks/quantile"
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/beorn7/perks/quantile"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// quantileLabel is used for the label that defines the quantile in a
|
||||
|
|
@ -146,6 +146,21 @@ type SummaryOpts struct {
|
|||
// is the internal buffer size of the underlying package
|
||||
// "github.com/bmizerany/perks/quantile").
|
||||
BufCap uint32
|
||||
|
||||
// now is for testing purposes, by default it's time.Now.
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
// SummaryVecOpts bundles the options to create a SummaryVec metric.
|
||||
// It is mandatory to set SummaryOpts, see there for mandatory fields. VariableLabels
|
||||
// is optional and can safely be left to its default value.
|
||||
type SummaryVecOpts struct {
|
||||
SummaryOpts
|
||||
|
||||
// VariableLabels are used to partition the metric vector by the given set
|
||||
// of labels. Each label value will be constrained with the optional Constraint
|
||||
// function, if provided.
|
||||
VariableLabels ConstrainableLabels
|
||||
}
|
||||
|
||||
// Problem with the sliding-window decay algorithm... The Merge method of
|
||||
|
|
@ -177,11 +192,11 @@ func NewSummary(opts SummaryOpts) Summary {
|
|||
}
|
||||
|
||||
func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
|
||||
if len(desc.variableLabels) != len(labelValues) {
|
||||
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues))
|
||||
if len(desc.variableLabels.names) != len(labelValues) {
|
||||
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels.names, labelValues))
|
||||
}
|
||||
|
||||
for _, n := range desc.variableLabels {
|
||||
for _, n := range desc.variableLabels.names {
|
||||
if n == quantileLabel {
|
||||
panic(errQuantileLabelNotAllowed)
|
||||
}
|
||||
|
|
@ -211,6 +226,9 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
|
|||
opts.BufCap = DefBufCap
|
||||
}
|
||||
|
||||
if opts.now == nil {
|
||||
opts.now = time.Now
|
||||
}
|
||||
if len(opts.Objectives) == 0 {
|
||||
// Use the lock-free implementation of a Summary without objectives.
|
||||
s := &noObjectivesSummary{
|
||||
|
|
@ -219,6 +237,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
|
|||
counts: [2]*summaryCounts{{}, {}},
|
||||
}
|
||||
s.init(s) // Init self-collection.
|
||||
s.createdTs = timestamppb.New(opts.now())
|
||||
return s
|
||||
}
|
||||
|
||||
|
|
@ -234,7 +253,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
|
|||
coldBuf: make([]float64, 0, opts.BufCap),
|
||||
streamDuration: opts.MaxAge / time.Duration(opts.AgeBuckets),
|
||||
}
|
||||
s.headStreamExpTime = time.Now().Add(s.streamDuration)
|
||||
s.headStreamExpTime = opts.now().Add(s.streamDuration)
|
||||
s.hotBufExpTime = s.headStreamExpTime
|
||||
|
||||
for i := uint32(0); i < opts.AgeBuckets; i++ {
|
||||
|
|
@ -248,6 +267,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
|
|||
sort.Float64s(s.sortedObjectives)
|
||||
|
||||
s.init(s) // Init self-collection.
|
||||
s.createdTs = timestamppb.New(opts.now())
|
||||
return s
|
||||
}
|
||||
|
||||
|
|
@ -275,6 +295,8 @@ type summary struct {
|
|||
headStream *quantile.Stream
|
||||
headStreamIdx int
|
||||
headStreamExpTime, hotBufExpTime time.Time
|
||||
|
||||
createdTs *timestamppb.Timestamp
|
||||
}
|
||||
|
||||
func (s *summary) Desc() *Desc {
|
||||
|
|
@ -296,7 +318,9 @@ func (s *summary) Observe(v float64) {
|
|||
}
|
||||
|
||||
func (s *summary) Write(out *dto.Metric) error {
|
||||
sum := &dto.Summary{}
|
||||
sum := &dto.Summary{
|
||||
CreatedTimestamp: s.createdTs,
|
||||
}
|
||||
qs := make([]*dto.Quantile, 0, len(s.objectives))
|
||||
|
||||
s.bufMtx.Lock()
|
||||
|
|
@ -429,6 +453,8 @@ type noObjectivesSummary struct {
|
|||
counts [2]*summaryCounts
|
||||
|
||||
labelPairs []*dto.LabelPair
|
||||
|
||||
createdTs *timestamppb.Timestamp
|
||||
}
|
||||
|
||||
func (s *noObjectivesSummary) Desc() *Desc {
|
||||
|
|
@ -479,8 +505,9 @@ func (s *noObjectivesSummary) Write(out *dto.Metric) error {
|
|||
}
|
||||
|
||||
sum := &dto.Summary{
|
||||
SampleCount: proto.Uint64(count),
|
||||
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
|
||||
SampleCount: proto.Uint64(count),
|
||||
SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))),
|
||||
CreatedTimestamp: s.createdTs,
|
||||
}
|
||||
|
||||
out.Summary = sum
|
||||
|
|
@ -530,20 +557,28 @@ type SummaryVec struct {
|
|||
// it is handled by the Prometheus server internally, “quantile” is an illegal
|
||||
// label name. NewSummaryVec will panic if this label name is used.
|
||||
func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
|
||||
for _, ln := range labelNames {
|
||||
return V2.NewSummaryVec(SummaryVecOpts{
|
||||
SummaryOpts: opts,
|
||||
VariableLabels: UnconstrainedLabels(labelNames),
|
||||
})
|
||||
}
|
||||
|
||||
// NewSummaryVec creates a new SummaryVec based on the provided SummaryVecOpts.
|
||||
func (v2) NewSummaryVec(opts SummaryVecOpts) *SummaryVec {
|
||||
for _, ln := range opts.VariableLabels.labelNames() {
|
||||
if ln == quantileLabel {
|
||||
panic(errQuantileLabelNotAllowed)
|
||||
}
|
||||
}
|
||||
desc := NewDesc(
|
||||
desc := V2.NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
labelNames,
|
||||
opts.VariableLabels,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
return &SummaryVec{
|
||||
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
|
||||
return newSummary(desc, opts, lvs...)
|
||||
return newSummary(desc, opts.SummaryOpts, lvs...)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
@ -662,6 +697,7 @@ type constSummary struct {
|
|||
sum float64
|
||||
quantiles map[float64]float64
|
||||
labelPairs []*dto.LabelPair
|
||||
createdTs *timestamppb.Timestamp
|
||||
}
|
||||
|
||||
func (s *constSummary) Desc() *Desc {
|
||||
|
|
@ -669,7 +705,9 @@ func (s *constSummary) Desc() *Desc {
|
|||
}
|
||||
|
||||
func (s *constSummary) Write(out *dto.Metric) error {
|
||||
sum := &dto.Summary{}
|
||||
sum := &dto.Summary{
|
||||
CreatedTimestamp: s.createdTs,
|
||||
}
|
||||
qs := make([]*dto.Quantile, 0, len(s.quantiles))
|
||||
|
||||
sum.SampleCount = proto.Uint64(s.count)
|
||||
|
|
@ -718,7 +756,7 @@ func NewConstSummary(
|
|||
if desc.err != nil {
|
||||
return nil, desc.err
|
||||
}
|
||||
if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
|
||||
if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &constSummary{
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ type Timer struct {
|
|||
}
|
||||
|
||||
// NewTimer creates a new Timer. The provided Observer is used to observe a
|
||||
// duration in seconds. Timer is usually used to time a function call in the
|
||||
// duration in seconds. If the Observer implements ExemplarObserver, passing exemplar
|
||||
// later on will be also supported.
|
||||
// Timer is usually used to time a function call in the
|
||||
// following way:
|
||||
//
|
||||
// func TimeMe() {
|
||||
|
|
@ -31,6 +33,14 @@ type Timer struct {
|
|||
// defer timer.ObserveDuration()
|
||||
// // Do actual work.
|
||||
// }
|
||||
//
|
||||
// or
|
||||
//
|
||||
// func TimeMeWithExemplar() {
|
||||
// timer := NewTimer(myHistogram)
|
||||
// defer timer.ObserveDurationWithExemplar(exemplar)
|
||||
// // Do actual work.
|
||||
// }
|
||||
func NewTimer(o Observer) *Timer {
|
||||
return &Timer{
|
||||
begin: time.Now(),
|
||||
|
|
@ -53,3 +63,19 @@ func (t *Timer) ObserveDuration() time.Duration {
|
|||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// ObserveDurationWithExemplar is like ObserveDuration, but it will also
|
||||
// observe exemplar with the duration unless exemplar is nil or provided Observer can't
|
||||
// be casted to ExemplarObserver.
|
||||
func (t *Timer) ObserveDurationWithExemplar(exemplar Labels) time.Duration {
|
||||
d := time.Since(t.begin)
|
||||
eo, ok := t.observer.(ExemplarObserver)
|
||||
if ok && exemplar != nil {
|
||||
eo.ObserveWithExemplar(d.Seconds(), exemplar)
|
||||
return d
|
||||
}
|
||||
if t.observer != nil {
|
||||
t.observer.Observe(d.Seconds())
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,18 +14,17 @@
|
|||
package prometheus
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/internal"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// ValueType is an enumeration of metric types that represent a simple value.
|
||||
|
|
@ -93,7 +92,7 @@ func (v *valueFunc) Desc() *Desc {
|
|||
}
|
||||
|
||||
func (v *valueFunc) Write(out *dto.Metric) error {
|
||||
return populateMetric(v.valType, v.function(), v.labelPairs, nil, out)
|
||||
return populateMetric(v.valType, v.function(), v.labelPairs, nil, out, nil)
|
||||
}
|
||||
|
||||
// NewConstMetric returns a metric with one fixed value that cannot be
|
||||
|
|
@ -107,12 +106,12 @@ func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues
|
|||
if desc.err != nil {
|
||||
return nil, desc.err
|
||||
}
|
||||
if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
|
||||
if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
metric := &dto.Metric{}
|
||||
if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric); err != nil {
|
||||
if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -132,6 +131,43 @@ func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelVal
|
|||
return m
|
||||
}
|
||||
|
||||
// NewConstMetricWithCreatedTimestamp does the same thing as NewConstMetric, but generates Counters
|
||||
// with created timestamp set and returns an error for other metric types.
|
||||
func NewConstMetricWithCreatedTimestamp(desc *Desc, valueType ValueType, value float64, ct time.Time, labelValues ...string) (Metric, error) {
|
||||
if desc.err != nil {
|
||||
return nil, desc.err
|
||||
}
|
||||
if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch valueType {
|
||||
case CounterValue:
|
||||
break
|
||||
default:
|
||||
return nil, errors.New("created timestamps are only supported for counters")
|
||||
}
|
||||
|
||||
metric := &dto.Metric{}
|
||||
if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric, timestamppb.New(ct)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &constMetric{
|
||||
desc: desc,
|
||||
metric: metric,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MustNewConstMetricWithCreatedTimestamp is a version of NewConstMetricWithCreatedTimestamp that panics where
|
||||
// NewConstMetricWithCreatedTimestamp would have returned an error.
|
||||
func MustNewConstMetricWithCreatedTimestamp(desc *Desc, valueType ValueType, value float64, ct time.Time, labelValues ...string) Metric {
|
||||
m, err := NewConstMetricWithCreatedTimestamp(desc, valueType, value, ct, labelValues...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type constMetric struct {
|
||||
desc *Desc
|
||||
metric *dto.Metric
|
||||
|
|
@ -155,11 +191,12 @@ func populateMetric(
|
|||
labelPairs []*dto.LabelPair,
|
||||
e *dto.Exemplar,
|
||||
m *dto.Metric,
|
||||
ct *timestamppb.Timestamp,
|
||||
) error {
|
||||
m.Label = labelPairs
|
||||
switch t {
|
||||
case CounterValue:
|
||||
m.Counter = &dto.Counter{Value: proto.Float64(v), Exemplar: e}
|
||||
m.Counter = &dto.Counter{Value: proto.Float64(v), Exemplar: e, CreatedTimestamp: ct}
|
||||
case GaugeValue:
|
||||
m.Gauge = &dto.Gauge{Value: proto.Float64(v)}
|
||||
case UntypedValue:
|
||||
|
|
@ -178,19 +215,19 @@ func populateMetric(
|
|||
// This function is only needed for custom Metric implementations. See MetricVec
|
||||
// example.
|
||||
func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
|
||||
totalLen := len(desc.variableLabels) + len(desc.constLabelPairs)
|
||||
totalLen := len(desc.variableLabels.names) + len(desc.constLabelPairs)
|
||||
if totalLen == 0 {
|
||||
// Super fast path.
|
||||
return nil
|
||||
}
|
||||
if len(desc.variableLabels) == 0 {
|
||||
if len(desc.variableLabels.names) == 0 {
|
||||
// Moderately fast path.
|
||||
return desc.constLabelPairs
|
||||
}
|
||||
labelPairs := make([]*dto.LabelPair, 0, totalLen)
|
||||
for i, n := range desc.variableLabels {
|
||||
for i, l := range desc.variableLabels.names {
|
||||
labelPairs = append(labelPairs, &dto.LabelPair{
|
||||
Name: proto.String(n),
|
||||
Name: proto.String(l),
|
||||
Value: proto.String(labelValues[i]),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ func NewMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *MetricVec {
|
|||
// with a performance overhead (for creating and processing the Labels map).
|
||||
// See also the CounterVec example.
|
||||
func (m *MetricVec) DeleteLabelValues(lvs ...string) bool {
|
||||
lvs = constrainLabelValues(m.desc, lvs, m.curry)
|
||||
|
||||
h, err := m.hashLabelValues(lvs)
|
||||
if err != nil {
|
||||
return false
|
||||
|
|
@ -91,6 +93,9 @@ func (m *MetricVec) DeleteLabelValues(lvs ...string) bool {
|
|||
// This method is used for the same purpose as DeleteLabelValues(...string). See
|
||||
// there for pros and cons of the two methods.
|
||||
func (m *MetricVec) Delete(labels Labels) bool {
|
||||
labels, closer := constrainLabels(m.desc, labels)
|
||||
defer closer()
|
||||
|
||||
h, err := m.hashLabels(labels)
|
||||
if err != nil {
|
||||
return false
|
||||
|
|
@ -106,6 +111,9 @@ func (m *MetricVec) Delete(labels Labels) bool {
|
|||
// Note that curried labels will never be matched if deleting from the curried vector.
|
||||
// To match curried labels with DeletePartialMatch, it must be called on the base vector.
|
||||
func (m *MetricVec) DeletePartialMatch(labels Labels) int {
|
||||
labels, closer := constrainLabels(m.desc, labels)
|
||||
defer closer()
|
||||
|
||||
return m.metricMap.deleteByLabels(labels, m.curry)
|
||||
}
|
||||
|
||||
|
|
@ -144,11 +152,11 @@ func (m *MetricVec) CurryWith(labels Labels) (*MetricVec, error) {
|
|||
oldCurry = m.curry
|
||||
iCurry int
|
||||
)
|
||||
for i, label := range m.desc.variableLabels {
|
||||
val, ok := labels[label]
|
||||
for i, labelName := range m.desc.variableLabels.names {
|
||||
val, ok := labels[labelName]
|
||||
if iCurry < len(oldCurry) && oldCurry[iCurry].index == i {
|
||||
if ok {
|
||||
return nil, fmt.Errorf("label name %q is already curried", label)
|
||||
return nil, fmt.Errorf("label name %q is already curried", labelName)
|
||||
}
|
||||
newCurry = append(newCurry, oldCurry[iCurry])
|
||||
iCurry++
|
||||
|
|
@ -156,7 +164,10 @@ func (m *MetricVec) CurryWith(labels Labels) (*MetricVec, error) {
|
|||
if !ok {
|
||||
continue // Label stays uncurried.
|
||||
}
|
||||
newCurry = append(newCurry, curriedLabelValue{i, val})
|
||||
newCurry = append(newCurry, curriedLabelValue{
|
||||
i,
|
||||
m.desc.variableLabels.constrain(labelName, val),
|
||||
})
|
||||
}
|
||||
}
|
||||
if l := len(oldCurry) + len(labels) - len(newCurry); l > 0 {
|
||||
|
|
@ -199,6 +210,7 @@ func (m *MetricVec) CurryWith(labels Labels) (*MetricVec, error) {
|
|||
// a wrapper around MetricVec, implementing a vector for a specific Metric
|
||||
// implementation, for example GaugeVec.
|
||||
func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
|
||||
lvs = constrainLabelValues(m.desc, lvs, m.curry)
|
||||
h, err := m.hashLabelValues(lvs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -224,6 +236,9 @@ func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
|
|||
// around MetricVec, implementing a vector for a specific Metric implementation,
|
||||
// for example GaugeVec.
|
||||
func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) {
|
||||
labels, closer := constrainLabels(m.desc, labels)
|
||||
defer closer()
|
||||
|
||||
h, err := m.hashLabels(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -233,7 +248,7 @@ func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) {
|
|||
}
|
||||
|
||||
func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) {
|
||||
if err := validateLabelValues(vals, len(m.desc.variableLabels)-len(m.curry)); err != nil {
|
||||
if err := validateLabelValues(vals, len(m.desc.variableLabels.names)-len(m.curry)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +257,7 @@ func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) {
|
|||
curry = m.curry
|
||||
iVals, iCurry int
|
||||
)
|
||||
for i := 0; i < len(m.desc.variableLabels); i++ {
|
||||
for i := 0; i < len(m.desc.variableLabels.names); i++ {
|
||||
if iCurry < len(curry) && curry[iCurry].index == i {
|
||||
h = m.hashAdd(h, curry[iCurry].value)
|
||||
iCurry++
|
||||
|
|
@ -256,7 +271,7 @@ func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) {
|
|||
}
|
||||
|
||||
func (m *MetricVec) hashLabels(labels Labels) (uint64, error) {
|
||||
if err := validateValuesInLabels(labels, len(m.desc.variableLabels)-len(m.curry)); err != nil {
|
||||
if err := validateValuesInLabels(labels, len(m.desc.variableLabels.names)-len(m.curry)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
|
@ -265,17 +280,17 @@ func (m *MetricVec) hashLabels(labels Labels) (uint64, error) {
|
|||
curry = m.curry
|
||||
iCurry int
|
||||
)
|
||||
for i, label := range m.desc.variableLabels {
|
||||
val, ok := labels[label]
|
||||
for i, labelName := range m.desc.variableLabels.names {
|
||||
val, ok := labels[labelName]
|
||||
if iCurry < len(curry) && curry[iCurry].index == i {
|
||||
if ok {
|
||||
return 0, fmt.Errorf("label name %q is already curried", label)
|
||||
return 0, fmt.Errorf("label name %q is already curried", labelName)
|
||||
}
|
||||
h = m.hashAdd(h, curry[iCurry].value)
|
||||
iCurry++
|
||||
} else {
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("label name %q missing in label map", label)
|
||||
return 0, fmt.Errorf("label name %q missing in label map", labelName)
|
||||
}
|
||||
h = m.hashAdd(h, val)
|
||||
}
|
||||
|
|
@ -453,7 +468,7 @@ func valueMatchesVariableOrCurriedValue(targetValue string, index int, values []
|
|||
func matchPartialLabels(desc *Desc, values []string, labels Labels, curry []curriedLabelValue) bool {
|
||||
for l, v := range labels {
|
||||
// Check if the target label exists in our metrics and get the index.
|
||||
varLabelIndex, validLabel := indexOf(l, desc.variableLabels)
|
||||
varLabelIndex, validLabel := indexOf(l, desc.variableLabels.names)
|
||||
if validLabel {
|
||||
// Check the value of that label against the target value.
|
||||
// We don't consider curried values in partial matches.
|
||||
|
|
@ -597,7 +612,7 @@ func matchLabels(desc *Desc, values []string, labels Labels, curry []curriedLabe
|
|||
return false
|
||||
}
|
||||
iCurry := 0
|
||||
for i, k := range desc.variableLabels {
|
||||
for i, k := range desc.variableLabels.names {
|
||||
if iCurry < len(curry) && curry[iCurry].index == i {
|
||||
if values[i] != curry[iCurry].value {
|
||||
return false
|
||||
|
|
@ -615,7 +630,7 @@ func matchLabels(desc *Desc, values []string, labels Labels, curry []curriedLabe
|
|||
func extractLabelValues(desc *Desc, labels Labels, curry []curriedLabelValue) []string {
|
||||
labelValues := make([]string, len(labels)+len(curry))
|
||||
iCurry := 0
|
||||
for i, k := range desc.variableLabels {
|
||||
for i, k := range desc.variableLabels.names {
|
||||
if iCurry < len(curry) && curry[iCurry].index == i {
|
||||
labelValues[i] = curry[iCurry].value
|
||||
iCurry++
|
||||
|
|
@ -640,3 +655,55 @@ func inlineLabelValues(lvs []string, curry []curriedLabelValue) []string {
|
|||
}
|
||||
return labelValues
|
||||
}
|
||||
|
||||
var labelsPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make(Labels)
|
||||
},
|
||||
}
|
||||
|
||||
func constrainLabels(desc *Desc, labels Labels) (Labels, func()) {
|
||||
if len(desc.variableLabels.labelConstraints) == 0 {
|
||||
// Fast path when there's no constraints
|
||||
return labels, func() {}
|
||||
}
|
||||
|
||||
constrainedLabels := labelsPool.Get().(Labels)
|
||||
for l, v := range labels {
|
||||
constrainedLabels[l] = desc.variableLabels.constrain(l, v)
|
||||
}
|
||||
|
||||
return constrainedLabels, func() {
|
||||
for k := range constrainedLabels {
|
||||
delete(constrainedLabels, k)
|
||||
}
|
||||
labelsPool.Put(constrainedLabels)
|
||||
}
|
||||
}
|
||||
|
||||
func constrainLabelValues(desc *Desc, lvs []string, curry []curriedLabelValue) []string {
|
||||
if len(desc.variableLabels.labelConstraints) == 0 {
|
||||
// Fast path when there's no constraints
|
||||
return lvs
|
||||
}
|
||||
|
||||
constrainedValues := make([]string, len(lvs))
|
||||
var iCurry, iLVs int
|
||||
for i := 0; i < len(lvs)+len(curry); i++ {
|
||||
if iCurry < len(curry) && curry[iCurry].index == i {
|
||||
iCurry++
|
||||
continue
|
||||
}
|
||||
|
||||
if i < len(desc.variableLabels.names) {
|
||||
constrainedValues[iLVs] = desc.variableLabels.constrain(
|
||||
desc.variableLabels.names[i],
|
||||
lvs[iLVs],
|
||||
)
|
||||
} else {
|
||||
constrainedValues[iLVs] = lvs[iLVs]
|
||||
}
|
||||
iLVs++
|
||||
}
|
||||
return constrainedValues
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2022 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus
|
||||
|
||||
type v2 struct{}
|
||||
|
||||
// V2 is a struct that can be referenced to access experimental API that might
|
||||
// be present in v2 of client golang someday. It offers extended functionality
|
||||
// of v1 with slightly changed API. It is acceptable to use some pieces from v1
|
||||
// and e.g `prometheus.NewGauge` and some from v2 e.g. `prometheus.V2.NewDesc`
|
||||
// in the same codebase.
|
||||
var V2 = v2{}
|
||||
|
|
@ -17,12 +17,10 @@ import (
|
|||
"fmt"
|
||||
"sort"
|
||||
|
||||
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/prometheus/client_golang/prometheus/internal"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/internal"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// WrapRegistererWith returns a Registerer wrapping the provided
|
||||
|
|
@ -206,7 +204,7 @@ func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc {
|
|||
constLabels[ln] = lv
|
||||
}
|
||||
// NewDesc will do remaining validations.
|
||||
newDesc := NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels)
|
||||
newDesc := V2.NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels)
|
||||
// Propagate errors if there was any. This will override any errer
|
||||
// created by NewDesc above, i.e. earlier errors get precedence.
|
||||
if desc.err != nil {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -132,7 +132,10 @@ func (d *textDecoder) Decode(v *dto.MetricFamily) error {
|
|||
}
|
||||
// Pick off one MetricFamily per Decode until there's nothing left.
|
||||
for key, fam := range d.fams {
|
||||
*v = *fam
|
||||
v.Name = fam.Name
|
||||
v.Help = fam.Help
|
||||
v.Type = fam.Type
|
||||
v.Metric = fam.Metric
|
||||
delete(d.fams, key)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
||||
"github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg"
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
|
@ -99,8 +99,11 @@ func NegotiateIncludingOpenMetrics(h http.Header) Format {
|
|||
if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
|
||||
return FmtText
|
||||
}
|
||||
if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion || ver == "") {
|
||||
return FmtOpenMetrics
|
||||
if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion_0_0_1 || ver == OpenMetricsVersion_1_0_0 || ver == "") {
|
||||
if ver == OpenMetricsVersion_1_0_0 {
|
||||
return FmtOpenMetrics_1_0_0
|
||||
}
|
||||
return FmtOpenMetrics_0_0_1
|
||||
}
|
||||
}
|
||||
return FmtText
|
||||
|
|
@ -133,7 +136,7 @@ func NewEncoder(w io.Writer, format Format) Encoder {
|
|||
case FmtProtoText:
|
||||
return encoderCloser{
|
||||
encode: func(v *dto.MetricFamily) error {
|
||||
_, err := fmt.Fprintln(w, proto.MarshalTextString(v))
|
||||
_, err := fmt.Fprintln(w, prototext.Format(v))
|
||||
return err
|
||||
},
|
||||
close: func() error { return nil },
|
||||
|
|
@ -146,7 +149,7 @@ func NewEncoder(w io.Writer, format Format) Encoder {
|
|||
},
|
||||
close: func() error { return nil },
|
||||
}
|
||||
case FmtOpenMetrics:
|
||||
case FmtOpenMetrics_0_0_1, FmtOpenMetrics_1_0_0:
|
||||
return encoderCloser{
|
||||
encode: func(v *dto.MetricFamily) error {
|
||||
_, err := MetricFamilyToOpenMetrics(w, v)
|
||||
|
|
|
|||
|
|
@ -19,20 +19,22 @@ type Format string
|
|||
|
||||
// Constants to assemble the Content-Type values for the different wire protocols.
|
||||
const (
|
||||
TextVersion = "0.0.4"
|
||||
ProtoType = `application/vnd.google.protobuf`
|
||||
ProtoProtocol = `io.prometheus.client.MetricFamily`
|
||||
ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
|
||||
OpenMetricsType = `application/openmetrics-text`
|
||||
OpenMetricsVersion = "0.0.1"
|
||||
TextVersion = "0.0.4"
|
||||
ProtoType = `application/vnd.google.protobuf`
|
||||
ProtoProtocol = `io.prometheus.client.MetricFamily`
|
||||
ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
|
||||
OpenMetricsType = `application/openmetrics-text`
|
||||
OpenMetricsVersion_0_0_1 = "0.0.1"
|
||||
OpenMetricsVersion_1_0_0 = "1.0.0"
|
||||
|
||||
// The Content-Type values for the different wire protocols.
|
||||
FmtUnknown Format = `<unknown>`
|
||||
FmtText Format = `text/plain; version=` + TextVersion + `; charset=utf-8`
|
||||
FmtProtoDelim Format = ProtoFmt + ` encoding=delimited`
|
||||
FmtProtoText Format = ProtoFmt + ` encoding=text`
|
||||
FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text`
|
||||
FmtOpenMetrics Format = OpenMetricsType + `; version=` + OpenMetricsVersion + `; charset=utf-8`
|
||||
FmtUnknown Format = `<unknown>`
|
||||
FmtText Format = `text/plain; version=` + TextVersion + `; charset=utf-8`
|
||||
FmtProtoDelim Format = ProtoFmt + ` encoding=delimited`
|
||||
FmtProtoText Format = ProtoFmt + ` encoding=text`
|
||||
FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text`
|
||||
FmtOpenMetrics_1_0_0 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_1_0_0 + `; charset=utf-8`
|
||||
FmtOpenMetrics_0_0_1 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_0_0_1 + `; charset=utf-8`
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import (
|
|||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/golang/protobuf/proto" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/prometheus/common/model"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// A stateFn is a function that represents a state in a state machine. By
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
linters:
|
||||
enable:
|
||||
- godot
|
||||
- misspell
|
||||
- revive
|
||||
|
||||
linter-settings:
|
||||
|
|
@ -10,3 +11,5 @@ linter-settings:
|
|||
exclude:
|
||||
# Ignore "See: URL"
|
||||
- 'See:'
|
||||
misspell:
|
||||
locale: US
|
||||
|
|
|
|||
|
|
@ -49,19 +49,19 @@ endif
|
|||
GOTEST := $(GO) test
|
||||
GOTEST_DIR :=
|
||||
ifneq ($(CIRCLE_JOB),)
|
||||
ifneq ($(shell which gotestsum),)
|
||||
ifneq ($(shell command -v gotestsum > /dev/null),)
|
||||
GOTEST_DIR := test-results
|
||||
GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml --
|
||||
endif
|
||||
endif
|
||||
|
||||
PROMU_VERSION ?= 0.14.0
|
||||
PROMU_VERSION ?= 0.15.0
|
||||
PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
|
||||
|
||||
SKIP_GOLANGCI_LINT :=
|
||||
GOLANGCI_LINT :=
|
||||
GOLANGCI_LINT_OPTS ?=
|
||||
GOLANGCI_LINT_VERSION ?= v1.49.0
|
||||
GOLANGCI_LINT_VERSION ?= v1.54.2
|
||||
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
|
||||
# windows isn't included here because of the path separator being different.
|
||||
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
|
||||
|
|
@ -91,6 +91,8 @@ BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS))
|
|||
PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS))
|
||||
TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS))
|
||||
|
||||
SANITIZED_DOCKER_IMAGE_TAG := $(subst +,-,$(DOCKER_IMAGE_TAG))
|
||||
|
||||
ifeq ($(GOHOSTARCH),amd64)
|
||||
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows))
|
||||
# Only supported on amd64
|
||||
|
|
@ -176,7 +178,7 @@ endif
|
|||
.PHONY: common-yamllint
|
||||
common-yamllint:
|
||||
@echo ">> running yamllint on all YAML files in the repository"
|
||||
ifeq (, $(shell which yamllint))
|
||||
ifeq (, $(shell command -v yamllint > /dev/null))
|
||||
@echo "yamllint not installed so skipping"
|
||||
else
|
||||
yamllint .
|
||||
|
|
@ -205,7 +207,7 @@ common-tarball: promu
|
|||
.PHONY: common-docker $(BUILD_DOCKER_ARCHS)
|
||||
common-docker: $(BUILD_DOCKER_ARCHS)
|
||||
$(BUILD_DOCKER_ARCHS): common-docker-%:
|
||||
docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \
|
||||
docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \
|
||||
-f $(DOCKERFILE_PATH) \
|
||||
--build-arg ARCH="$*" \
|
||||
--build-arg OS="linux" \
|
||||
|
|
@ -214,19 +216,19 @@ $(BUILD_DOCKER_ARCHS): common-docker-%:
|
|||
.PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS)
|
||||
common-docker-publish: $(PUBLISH_DOCKER_ARCHS)
|
||||
$(PUBLISH_DOCKER_ARCHS): common-docker-publish-%:
|
||||
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)"
|
||||
docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)"
|
||||
|
||||
DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION)))
|
||||
.PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS)
|
||||
common-docker-tag-latest: $(TAG_DOCKER_ARCHS)
|
||||
$(TAG_DOCKER_ARCHS): common-docker-tag-latest-%:
|
||||
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
|
||||
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)"
|
||||
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest"
|
||||
docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)"
|
||||
|
||||
.PHONY: common-docker-manifest
|
||||
common-docker-manifest:
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG))
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)"
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(SANITIZED_DOCKER_IMAGE_TAG))
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)"
|
||||
|
||||
.PHONY: promu
|
||||
promu: $(PROMU)
|
||||
|
|
|
|||
|
|
@ -51,11 +51,11 @@ ensure the `fixtures` directory is up to date by removing the existing directory
|
|||
extracting the ttar file using `make fixtures/.unpacked` or just `make test`.
|
||||
|
||||
```bash
|
||||
rm -rf fixtures
|
||||
rm -rf testdata/fixtures
|
||||
make test
|
||||
```
|
||||
|
||||
Next, make the required changes to the extracted files in the `fixtures` directory. When
|
||||
the changes are complete, run `make update_fixtures` to create a new `fixtures.ttar` file
|
||||
based on the updated `fixtures` directory. And finally, verify the changes using
|
||||
`git diff fixtures.ttar`.
|
||||
`git diff testdata/fixtures.ttar`.
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ type ARPEntry struct {
|
|||
func (fs FS) GatherARPEntries() ([]ARPEntry, error) {
|
||||
data, err := os.ReadFile(fs.proc.Path("net/arp"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading arp %q: %w", fs.proc.Path("net/arp"), err)
|
||||
return nil, fmt.Errorf("%s: error reading arp %s: %w", ErrFileRead, fs.proc.Path("net/arp"), err)
|
||||
}
|
||||
|
||||
return parseARPEntries(data)
|
||||
|
|
@ -78,11 +78,11 @@ func parseARPEntries(data []byte) ([]ARPEntry, error) {
|
|||
} else if width == expectedDataWidth {
|
||||
entry, err := parseARPEntry(columns)
|
||||
if err != nil {
|
||||
return []ARPEntry{}, fmt.Errorf("failed to parse ARP entry: %w", err)
|
||||
return []ARPEntry{}, fmt.Errorf("%s: Failed to parse ARP entry: %v: %w", ErrFileParse, entry, err)
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
} else {
|
||||
return []ARPEntry{}, fmt.Errorf("%d columns were detected, but %d were expected", width, expectedDataWidth)
|
||||
return []ARPEntry{}, fmt.Errorf("%s: %d columns found, but expected %d: %w", ErrFileParse, width, expectedDataWidth, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
|
|||
parts := strings.Fields(line)
|
||||
|
||||
if len(parts) < 4 {
|
||||
return nil, fmt.Errorf("invalid number of fields when parsing buddyinfo")
|
||||
return nil, fmt.Errorf("%w: Invalid number of fields, found: %v", ErrFileParse, parts)
|
||||
}
|
||||
|
||||
node := strings.TrimRight(parts[1], ",")
|
||||
|
|
@ -66,7 +66,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
|
|||
bucketCount = arraySize
|
||||
} else {
|
||||
if bucketCount != arraySize {
|
||||
return nil, fmt.Errorf("mismatch in number of buddyinfo buckets, previous count %d, new count %d", bucketCount, arraySize)
|
||||
return nil, fmt.Errorf("%w: mismatch in number of buddyinfo buckets, previous count %d, new count %d", ErrFileParse, bucketCount, arraySize)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
|
|||
for i := 0; i < arraySize; i++ {
|
||||
sizes[i], err = strconv.ParseFloat(parts[i+4], 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid value in buddyinfo: %w", err)
|
||||
return nil, fmt.Errorf("%s: Invalid valid in buddyinfo: %f: %w", ErrFileParse, sizes[i], err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ func parseCPUInfoX86(info []byte) ([]CPUInfo, error) {
|
|||
// find the first "processor" line
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
return nil, fmt.Errorf("%w: Cannot parse line: %q", ErrFileParse, firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
|
|
@ -192,9 +192,10 @@ func parseCPUInfoARM(info []byte) ([]CPUInfo, error) {
|
|||
scanner := bufio.NewScanner(bytes.NewReader(info))
|
||||
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
match, _ := regexp.MatchString("^[Pp]rocessor", firstLine)
|
||||
match, err := regexp.MatchString("^[Pp]rocessor", firstLine)
|
||||
if !match || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
return nil, fmt.Errorf("%s: Cannot parse line: %q: %w", ErrFileParse, firstLine, err)
|
||||
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
cpuinfo := []CPUInfo{}
|
||||
|
|
@ -258,7 +259,7 @@ func parseCPUInfoS390X(info []byte) ([]CPUInfo, error) {
|
|||
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "vendor_id") || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
return nil, fmt.Errorf("%w: Cannot parse line: %q", ErrFileParse, firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
cpuinfo := []CPUInfo{}
|
||||
|
|
@ -283,7 +284,7 @@ func parseCPUInfoS390X(info []byte) ([]CPUInfo, error) {
|
|||
if strings.HasPrefix(line, "processor") {
|
||||
match := cpuinfoS390XProcessorRegexp.FindStringSubmatch(line)
|
||||
if len(match) < 2 {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
return nil, fmt.Errorf("%w: %q", ErrFileParse, firstLine)
|
||||
}
|
||||
cpu := commonCPUInfo
|
||||
v, err := strconv.ParseUint(match[1], 0, 32)
|
||||
|
|
@ -343,7 +344,7 @@ func parseCPUInfoMips(info []byte) ([]CPUInfo, error) {
|
|||
// find the first "processor" line
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "system type") || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
return nil, fmt.Errorf("%w: %q", ErrFileParse, firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
cpuinfo := []CPUInfo{}
|
||||
|
|
@ -421,7 +422,7 @@ func parseCPUInfoPPC(info []byte) ([]CPUInfo, error) {
|
|||
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
return nil, fmt.Errorf("%w: %q", ErrFileParse, firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
|
|
@ -466,7 +467,7 @@ func parseCPUInfoRISCV(info []byte) ([]CPUInfo, error) {
|
|||
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine)
|
||||
return nil, fmt.Errorf("%w: %q", ErrFileParse, firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
v, err := strconv.ParseUint(field[1], 0, 32)
|
||||
|
|
|
|||
|
|
@ -55,12 +55,13 @@ func (fs FS) Crypto() ([]Crypto, error) {
|
|||
path := fs.proc.Path("crypto")
|
||||
b, err := util.ReadFileNoStat(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading crypto %q: %w", path, err)
|
||||
return nil, fmt.Errorf("%s: Cannot read file %v: %w", ErrFileRead, b, err)
|
||||
|
||||
}
|
||||
|
||||
crypto, err := parseCrypto(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing crypto %q: %w", path, err)
|
||||
return nil, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, crypto, err)
|
||||
}
|
||||
|
||||
return crypto, nil
|
||||
|
|
@ -83,7 +84,7 @@ func parseCrypto(r io.Reader) ([]Crypto, error) {
|
|||
|
||||
kv := strings.Split(text, ":")
|
||||
if len(kv) != 2 {
|
||||
return nil, fmt.Errorf("malformed crypto line: %q", text)
|
||||
return nil, fmt.Errorf("%w: Cannot parae line: %q", ErrFileParse, text)
|
||||
}
|
||||
|
||||
k := strings.TrimSpace(kv[0])
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ import (
|
|||
// FS represents the pseudo-filesystem sys, which provides an interface to
|
||||
// kernel data structures.
|
||||
type FS struct {
|
||||
proc fs.FS
|
||||
proc fs.FS
|
||||
isReal bool
|
||||
}
|
||||
|
||||
// DefaultMountPoint is the common mount point of the proc filesystem.
|
||||
|
|
@ -39,5 +40,11 @@ func NewFS(mountPoint string) (FS, error) {
|
|||
if err != nil {
|
||||
return FS{}, err
|
||||
}
|
||||
return FS{fs}, nil
|
||||
|
||||
isReal, err := isRealProc(mountPoint)
|
||||
if err != nil {
|
||||
return FS{}, err
|
||||
}
|
||||
|
||||
return FS{fs, isReal}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !freebsd && !linux
|
||||
// +build !freebsd,!linux
|
||||
|
||||
package procfs
|
||||
|
||||
// isRealProc returns true on architectures that don't have a Type argument
|
||||
// in their Statfs_t struct
|
||||
func isRealProc(mountPoint string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2018 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build freebsd || linux
|
||||
// +build freebsd linux
|
||||
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// isRealProc determines whether supplied mountpoint is really a proc filesystem.
|
||||
func isRealProc(mountPoint string) (bool, error) {
|
||||
stat := syscall.Statfs_t{}
|
||||
err := syscall.Statfs(mountPoint, &stat)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 0x9fa0 is PROC_SUPER_MAGIC: https://elixir.bootlin.com/linux/v6.1/source/include/uapi/linux/magic.h#L87
|
||||
return stat.Type == 0x9fa0, nil
|
||||
}
|
||||
|
|
@ -236,7 +236,7 @@ func (fs FS) Fscacheinfo() (Fscacheinfo, error) {
|
|||
|
||||
m, err := parseFscacheinfo(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return Fscacheinfo{}, fmt.Errorf("failed to parse Fscacheinfo: %w", err)
|
||||
return Fscacheinfo{}, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, m, err)
|
||||
}
|
||||
|
||||
return *m, nil
|
||||
|
|
@ -245,7 +245,7 @@ func (fs FS) Fscacheinfo() (Fscacheinfo, error) {
|
|||
func setFSCacheFields(fields []string, setFields ...*uint64) error {
|
||||
var err error
|
||||
if len(fields) < len(setFields) {
|
||||
return fmt.Errorf("Insufficient number of fields, expected %v, got %v", len(setFields), len(fields))
|
||||
return fmt.Errorf("%s: Expected %d, but got %d: %w", ErrFileParse, len(setFields), len(fields), err)
|
||||
}
|
||||
|
||||
for i := range setFields {
|
||||
|
|
@ -263,7 +263,7 @@ func parseFscacheinfo(r io.Reader) (*Fscacheinfo, error) {
|
|||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
if len(fields) < 2 {
|
||||
return nil, fmt.Errorf("malformed Fscacheinfo line: %q", s.Text())
|
||||
return nil, fmt.Errorf("%w: malformed Fscacheinfo line: %q", ErrFileParse, s.Text())
|
||||
}
|
||||
|
||||
switch fields[0] {
|
||||
|
|
|
|||
|
|
@ -64,6 +64,21 @@ func ParsePInt64s(ss []string) ([]*int64, error) {
|
|||
return us, nil
|
||||
}
|
||||
|
||||
// Parses a uint64 from given hex in string.
|
||||
func ParseHexUint64s(ss []string) ([]*uint64, error) {
|
||||
us := make([]*uint64, 0, len(ss))
|
||||
for _, s := range ss {
|
||||
u, err := strconv.ParseUint(s, 16, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
us = append(us, &u)
|
||||
}
|
||||
|
||||
return us, nil
|
||||
}
|
||||
|
||||
// ReadUintFromFile reads a file and attempts to parse a uint64 from it.
|
||||
func ReadUintFromFile(path string) (uint64, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
|
|
|
|||
|
|
@ -221,15 +221,16 @@ func parseIPPort(s string) (net.IP, uint16, error) {
|
|||
case 46:
|
||||
ip = net.ParseIP(s[1:40])
|
||||
if ip == nil {
|
||||
return nil, 0, fmt.Errorf("invalid IPv6 address: %s", s[1:40])
|
||||
return nil, 0, fmt.Errorf("%s: Invalid IPv6 addr %s: %w", ErrFileParse, s[1:40], err)
|
||||
}
|
||||
default:
|
||||
return nil, 0, fmt.Errorf("unexpected IP:Port: %s", s)
|
||||
return nil, 0, fmt.Errorf("%s: Unexpected IP:Port %s: %w", ErrFileParse, s, err)
|
||||
}
|
||||
|
||||
portString := s[len(s)-4:]
|
||||
if len(portString) != 4 {
|
||||
return nil, 0, fmt.Errorf("unexpected port string format: %s", portString)
|
||||
return nil, 0,
|
||||
fmt.Errorf("%s: Unexpected port string format %s: %w", ErrFileParse, portString, err)
|
||||
}
|
||||
port, err := strconv.ParseUint(portString, 16, 16)
|
||||
if err != nil {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue