mirror of https://github.com/containers/podman.git
Merge pull request #23721 from containers/renovate/github.com-openshift-imagebuilder-1.x
Update module github.com/openshift/imagebuilder to v1.2.15
This commit is contained in:
commit
7156f60fee
9
go.mod
9
go.mod
|
@ -59,7 +59,7 @@ require (
|
||||||
github.com/opencontainers/runtime-spec v1.2.0
|
github.com/opencontainers/runtime-spec v1.2.0
|
||||||
github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc
|
github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc
|
||||||
github.com/opencontainers/selinux v1.11.0
|
github.com/opencontainers/selinux v1.11.0
|
||||||
github.com/openshift/imagebuilder v1.2.14
|
github.com/openshift/imagebuilder v1.2.15
|
||||||
github.com/rootless-containers/rootlesskit/v2 v2.2.0
|
github.com/rootless-containers/rootlesskit/v2 v2.2.0
|
||||||
github.com/shirou/gopsutil/v3 v3.24.5
|
github.com/shirou/gopsutil/v3 v3.24.5
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
|
@ -97,9 +97,10 @@ require (
|
||||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||||
github.com/chzyer/readline v1.5.1 // indirect
|
github.com/chzyer/readline v1.5.1 // indirect
|
||||||
github.com/containerd/cgroups/v3 v3.0.3 // indirect
|
github.com/containerd/cgroups/v3 v3.0.3 // indirect
|
||||||
github.com/containerd/containerd v1.7.18 // indirect
|
github.com/containerd/containerd v1.7.20 // indirect
|
||||||
github.com/containerd/errdefs v0.1.0 // indirect
|
github.com/containerd/errdefs v0.1.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
|
github.com/containerd/platforms v0.2.1 // indirect
|
||||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
|
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
|
||||||
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
||||||
github.com/containernetworking/cni v1.2.3 // indirect
|
github.com/containernetworking/cni v1.2.3 // indirect
|
||||||
|
@ -115,7 +116,7 @@ require (
|
||||||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
github.com/fsouza/go-dockerclient v1.11.1 // indirect
|
github.com/fsouza/go-dockerclient v1.11.2 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/gin-gonic/gin v1.9.1 // indirect
|
github.com/gin-gonic/gin v1.9.1 // indirect
|
||||||
|
@ -167,7 +168,7 @@ require (
|
||||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||||
github.com/mistifyio/go-zfs/v3 v3.0.1 // indirect
|
github.com/mistifyio/go-zfs/v3 v3.0.1 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/moby/buildkit v0.12.5 // indirect
|
github.com/moby/buildkit v0.15.1 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||||
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||||
|
|
18
go.sum
18
go.sum
|
@ -63,12 +63,14 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
|
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
|
||||||
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
|
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
|
||||||
github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao=
|
github.com/containerd/containerd v1.7.20 h1:Sl6jQYk3TRavaU83h66QMbI2Nqg9Jm6qzwX57Vsn1SQ=
|
||||||
github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4=
|
github.com/containerd/containerd v1.7.20/go.mod h1:52GsS5CwquuqPuLncsXwG0t2CiUce+KsNHJZQJvAgR0=
|
||||||
github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
|
github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
|
||||||
github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0=
|
github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
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/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
|
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||||
|
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU=
|
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/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
|
||||||
github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4=
|
github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4=
|
||||||
|
@ -161,8 +163,8 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw
|
||||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
github.com/fsouza/go-dockerclient v1.11.1 h1:i5Vk9riDxW2uP9pVS5FYkpquMTFT5lsx2pt7oErRTjI=
|
github.com/fsouza/go-dockerclient v1.11.2 h1:Wos4OMUwIjOW2rt8Z10TZSJHxgQH0KcYyf3O86dqFII=
|
||||||
github.com/fsouza/go-dockerclient v1.11.1/go.mod h1:UfjOOaspAq+RGh7GX1aZ0HeWWGHQWWsh+H5BgEWB3Pk=
|
github.com/fsouza/go-dockerclient v1.11.2/go.mod h1:HZN6ky2Mg5mfZO/WZBFDe6XCricqTnDJntfXHZTYnQQ=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
@ -357,8 +359,8 @@ github.com/mistifyio/go-zfs/v3 v3.0.1 h1:YaoXgBePoMA12+S1u/ddkv+QqxcfiZK4prI6HPn
|
||||||
github.com/mistifyio/go-zfs/v3 v3.0.1/go.mod h1:CzVgeB0RvF2EGzQnytKVvVSDwmKJXxkOTUGbNrTja/k=
|
github.com/mistifyio/go-zfs/v3 v3.0.1/go.mod h1:CzVgeB0RvF2EGzQnytKVvVSDwmKJXxkOTUGbNrTja/k=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
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/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.15.1 h1:J6wrew7hphKqlq1wuu6yaUb/1Ra7gEzDAovylGztAKM=
|
||||||
github.com/moby/buildkit v0.12.5/go.mod h1:YGwjA2loqyiYfZeEo8FtI7z4x5XponAaIWsWcSjWwso=
|
github.com/moby/buildkit v0.15.1/go.mod h1:Yis8ZMUJTHX9XhH9zVyK2igqSHV3sxi3UN0uztZocZk=
|
||||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||||
|
@ -400,8 +402,8 @@ github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc h1:
|
||||||
github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc/go.mod h1:8tx1helyqhUC65McMm3x7HmOex8lO2/v9zPuxmKHurs=
|
github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc/go.mod h1:8tx1helyqhUC65McMm3x7HmOex8lO2/v9zPuxmKHurs=
|
||||||
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
|
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
|
||||||
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||||
github.com/openshift/imagebuilder v1.2.14 h1:l4gUw0KIsjZrX7otfS4WoKxzGBrxYldU3pF4+5W/ud8=
|
github.com/openshift/imagebuilder v1.2.15 h1:MNn1OztEE/l8pSEDPYAQ71Ys6rpXA2P00UFhdY9p/yk=
|
||||||
github.com/openshift/imagebuilder v1.2.14/go.mod h1:KkkXOyRjJlZEXWQtHNBNzVHqh4vf/0xX5cDIQ2gr+5I=
|
github.com/openshift/imagebuilder v1.2.15/go.mod h1:cK6MLyBl1IHmIYGLY/2SLOG6p0PtEDUOC7khxsFYUXE=
|
||||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||||
github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f h1:/UDgs8FGMqwnHagNDPGOlts35QkhAZ8by3DR7nMih7M=
|
github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f h1:/UDgs8FGMqwnHagNDPGOlts35QkhAZ8by3DR7nMih7M=
|
||||||
|
|
|
@ -1,116 +0,0 @@
|
||||||
/*
|
|
||||||
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 errdefs defines the common errors used throughout containerd
|
|
||||||
// packages.
|
|
||||||
//
|
|
||||||
// Use with fmt.Errorf to add context to an error.
|
|
||||||
//
|
|
||||||
// To detect an error class, use the IsXXX functions to tell whether an error
|
|
||||||
// is of a certain type.
|
|
||||||
//
|
|
||||||
// The functions ToGRPC and FromGRPC can be used to map server-side and
|
|
||||||
// client-side errors to the correct types.
|
|
||||||
package errdefs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/containerd/errdefs"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Definitions of common error types used throughout containerd. All containerd
|
|
||||||
// errors returned by most packages will map into one of these errors classes.
|
|
||||||
// Packages should return errors of these types when they want to instruct a
|
|
||||||
// client to take a particular action.
|
|
||||||
//
|
|
||||||
// For the most part, we just try to provide local grpc errors. Most conditions
|
|
||||||
// map very well to those defined by grpc.
|
|
||||||
var (
|
|
||||||
ErrUnknown = errdefs.ErrUnknown
|
|
||||||
ErrInvalidArgument = errdefs.ErrInvalidArgument
|
|
||||||
ErrNotFound = errdefs.ErrNotFound
|
|
||||||
ErrAlreadyExists = errdefs.ErrAlreadyExists
|
|
||||||
ErrFailedPrecondition = errdefs.ErrFailedPrecondition
|
|
||||||
ErrUnavailable = errdefs.ErrUnavailable
|
|
||||||
ErrNotImplemented = errdefs.ErrNotImplemented
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsInvalidArgument returns true if the error is due to an invalid argument
|
|
||||||
func IsInvalidArgument(err error) bool {
|
|
||||||
return errdefs.IsInvalidArgument(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNotFound returns true if the error is due to a missing object
|
|
||||||
func IsNotFound(err error) bool {
|
|
||||||
return errdefs.IsNotFound(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAlreadyExists returns true if the error is due to an already existing
|
|
||||||
// metadata item
|
|
||||||
func IsAlreadyExists(err error) bool {
|
|
||||||
return errdefs.IsAlreadyExists(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsFailedPrecondition returns true if an operation could not proceed to the
|
|
||||||
// lack of a particular condition
|
|
||||||
func IsFailedPrecondition(err error) bool {
|
|
||||||
return errdefs.IsFailedPrecondition(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsUnavailable returns true if the error is due to a resource being unavailable
|
|
||||||
func IsUnavailable(err error) bool {
|
|
||||||
return errdefs.IsUnavailable(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNotImplemented returns true if the error is due to not being implemented
|
|
||||||
func IsNotImplemented(err error) bool {
|
|
||||||
return errdefs.IsNotImplemented(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCanceled returns true if the error is due to `context.Canceled`.
|
|
||||||
func IsCanceled(err error) bool {
|
|
||||||
return errdefs.IsCanceled(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDeadlineExceeded returns true if the error is due to
|
|
||||||
// `context.DeadlineExceeded`.
|
|
||||||
func IsDeadlineExceeded(err error) bool {
|
|
||||||
return errdefs.IsDeadlineExceeded(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToGRPC will attempt to map the backend containerd error into a grpc error,
|
|
||||||
// using the original error message as a description.
|
|
||||||
//
|
|
||||||
// Further information may be extracted from certain errors depending on their
|
|
||||||
// type.
|
|
||||||
//
|
|
||||||
// If the error is unmapped, the original error will be returned to be handled
|
|
||||||
// by the regular grpc error handling stack.
|
|
||||||
func ToGRPC(err error) error {
|
|
||||||
return errdefs.ToGRPC(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToGRPCf maps the error to grpc error codes, assembling the formatting string
|
|
||||||
// and combining it with the target error string.
|
|
||||||
//
|
|
||||||
// This is equivalent to errdefs.ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
|
|
||||||
func ToGRPCf(err error, format string, args ...interface{}) error {
|
|
||||||
return errdefs.ToGRPCf(err, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromGRPC returns the underlying error from a grpc service based on the grpc error code
|
|
||||||
func FromGRPC(err error) error {
|
|
||||||
return errdefs.FromGRPC(err)
|
|
||||||
}
|
|
176
vendor/github.com/containerd/containerd/platforms/platforms_deprecated.go
generated
vendored
Normal file
176
vendor/github.com/containerd/containerd/platforms/platforms_deprecated.go
generated
vendored
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
/*
|
||||||
|
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 platforms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containerd/platforms"
|
||||||
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Platform is a type alias for convenience, so there is no need to import image-spec package everywhere.
|
||||||
|
//
|
||||||
|
// Deprecated: use [specs.Platform].
|
||||||
|
type Platform = specs.Platform
|
||||||
|
|
||||||
|
// DefaultSpec returns the current platform's default platform specification.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.DefaultSpec].
|
||||||
|
func DefaultSpec() specs.Platform {
|
||||||
|
return platforms.DefaultSpec()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default returns the default matcher for the platform.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.Default].
|
||||||
|
func Default() platforms.MatchComparer {
|
||||||
|
return platforms.Default()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultString returns the default string specifier for the platform.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.DefaultString].
|
||||||
|
func DefaultString() string {
|
||||||
|
return platforms.Format(platforms.DefaultSpec()) // For 1.7 continue using the old format without os-version included.
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultStrict returns strict form of Default.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.DefaultStrict].
|
||||||
|
func DefaultStrict() MatchComparer {
|
||||||
|
return platforms.DefaultStrict()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchComparer is able to match and compare platforms to
|
||||||
|
// filter and sort platforms.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.MatchComparer].
|
||||||
|
type MatchComparer = platforms.MatchComparer
|
||||||
|
|
||||||
|
// Matcher matches platforms specifications, provided by an image or runtime.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.Matcher].
|
||||||
|
type Matcher = platforms.Matcher
|
||||||
|
|
||||||
|
// NewMatcher returns a simple matcher based on the provided platform
|
||||||
|
// specification. The returned matcher only looks for equality based on os,
|
||||||
|
// architecture and variant.
|
||||||
|
//
|
||||||
|
// One may implement their own matcher if this doesn't provide the required
|
||||||
|
// functionality.
|
||||||
|
//
|
||||||
|
// Applications should opt to use `Match` over directly parsing specifiers.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.NewMatcher].
|
||||||
|
func NewMatcher(platform specs.Platform) platforms.Matcher {
|
||||||
|
return platforms.NewMatcher(platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses the platform specifier syntax into a platform declaration.
|
||||||
|
//
|
||||||
|
// Platform specifiers are in the format `<os>|<arch>|<os>/<arch>[/<variant>]`.
|
||||||
|
// The minimum required information for a platform specifier is the operating
|
||||||
|
// system or architecture. If there is only a single string (no slashes), the
|
||||||
|
// value will be matched against the known set of operating systems, then fall
|
||||||
|
// back to the known set of architectures. The missing component will be
|
||||||
|
// inferred based on the local environment.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.Parse].
|
||||||
|
func Parse(specifier string) (specs.Platform, error) {
|
||||||
|
return platforms.Parse(specifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustParse is like Parses but panics if the specifier cannot be parsed.
|
||||||
|
// Simplifies initialization of global variables.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.MustParse].
|
||||||
|
func MustParse(specifier string) specs.Platform {
|
||||||
|
return platforms.MustParse(specifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format returns a string specifier from the provided platform specification.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.Format].
|
||||||
|
func Format(platform specs.Platform) string {
|
||||||
|
return platforms.Format(platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize validates and translate the platform to the canonical value.
|
||||||
|
//
|
||||||
|
// For example, if "Aarch64" is encountered, we change it to "arm64" or if
|
||||||
|
// "x86_64" is encountered, it becomes "amd64".
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.Normalize].
|
||||||
|
func Normalize(platform specs.Platform) specs.Platform {
|
||||||
|
return platforms.Normalize(platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only returns a match comparer for a single platform
|
||||||
|
// using default resolution logic for the platform.
|
||||||
|
//
|
||||||
|
// For arm/v8, will also match arm/v7, arm/v6 and arm/v5
|
||||||
|
// For arm/v7, will also match arm/v6 and arm/v5
|
||||||
|
// For arm/v6, will also match arm/v5
|
||||||
|
// For amd64, will also match 386
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.Only].
|
||||||
|
func Only(platform specs.Platform) platforms.MatchComparer {
|
||||||
|
return platforms.Only(platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnlyStrict returns a match comparer for a single platform.
|
||||||
|
//
|
||||||
|
// Unlike Only, OnlyStrict does not match sub platforms.
|
||||||
|
// So, "arm/vN" will not match "arm/vM" where M < N,
|
||||||
|
// and "amd64" will not also match "386".
|
||||||
|
//
|
||||||
|
// OnlyStrict matches non-canonical forms.
|
||||||
|
// So, "arm64" matches "arm/64/v8".
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.OnlyStrict].
|
||||||
|
func OnlyStrict(platform specs.Platform) platforms.MatchComparer {
|
||||||
|
return platforms.OnlyStrict(platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ordered returns a platform MatchComparer which matches any of the platforms
|
||||||
|
// but orders them in order they are provided.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.Ordered].
|
||||||
|
func Ordered(platform ...specs.Platform) platforms.MatchComparer {
|
||||||
|
return platforms.Ordered(platform...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any returns a platform MatchComparer which matches any of the platforms
|
||||||
|
// with no preference for ordering.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.Any].
|
||||||
|
func Any(platform ...specs.Platform) platforms.MatchComparer {
|
||||||
|
return platforms.Any(platform...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// All is a platform MatchComparer which matches all platforms
|
||||||
|
// with preference for ordering.
|
||||||
|
//
|
||||||
|
// Deprecated: use [platforms.All].
|
||||||
|
var All = platforms.All
|
||||||
|
|
||||||
|
// GetWindowsOsVersion returns the version of Windows of the local system,
|
||||||
|
// it returns an empty string on other platforms.
|
||||||
|
//
|
||||||
|
// Deprecated: this function is deprecated, and removed in github.com/containerd/platforms
|
||||||
|
func GetWindowsOsVersion() string {
|
||||||
|
return getWindowsOsVersion()
|
||||||
|
}
|
23
vendor/github.com/containerd/containerd/platforms/platforms_deprecated_other.go
generated
vendored
Normal file
23
vendor/github.com/containerd/containerd/platforms/platforms_deprecated_other.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 platforms
|
||||||
|
|
||||||
|
func getWindowsOsVersion() string {
|
||||||
|
return ""
|
||||||
|
}
|
49
vendor/github.com/containerd/containerd/platforms/platforms_deprecated_windows.go
generated
vendored
Normal file
49
vendor/github.com/containerd/containerd/platforms/platforms_deprecated_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
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 platforms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/osversion"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getWindowsOsVersion() string {
|
||||||
|
major, minor, build := windows.RtlGetNtVersionNumbers()
|
||||||
|
return fmt.Sprintf("%d.%d.%d", major, minor, build)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: this function is deprecated, and removed in github.com/containerd/platforms
|
||||||
|
func GetOsVersion(osVersionPrefix string) osversion.OSVersion {
|
||||||
|
parts := strings.Split(osVersionPrefix, ".")
|
||||||
|
if len(parts) < 3 {
|
||||||
|
return osversion.OSVersion{}
|
||||||
|
}
|
||||||
|
|
||||||
|
majorVersion, _ := strconv.Atoi(parts[0])
|
||||||
|
minorVersion, _ := strconv.Atoi(parts[1])
|
||||||
|
buildNumber, _ := strconv.Atoi(parts[2])
|
||||||
|
|
||||||
|
return osversion.OSVersion{
|
||||||
|
MajorVersion: uint8(majorVersion),
|
||||||
|
MinorVersion: uint8(minorVersion),
|
||||||
|
Build: uint16(buildNumber),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
*.go text eol=lf
|
|
@ -0,0 +1,30 @@
|
||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
- exportloopref # Checks for pointers to enclosing loop variables
|
||||||
|
- gofmt
|
||||||
|
- goimports
|
||||||
|
- gosec
|
||||||
|
- ineffassign
|
||||||
|
- misspell
|
||||||
|
- nolintlint
|
||||||
|
- revive
|
||||||
|
- staticcheck
|
||||||
|
- tenv # Detects using os.Setenv instead of t.Setenv since Go 1.17
|
||||||
|
- unconvert
|
||||||
|
- unused
|
||||||
|
- vet
|
||||||
|
- dupword # Checks for duplicate words in the source code
|
||||||
|
disable:
|
||||||
|
- errcheck
|
||||||
|
|
||||||
|
run:
|
||||||
|
timeout: 5m
|
||||||
|
skip-dirs:
|
||||||
|
- api
|
||||||
|
- cluster
|
||||||
|
- design
|
||||||
|
- docs
|
||||||
|
- docs/man
|
||||||
|
- releases
|
||||||
|
- reports
|
||||||
|
- test # e2e scripts
|
|
@ -0,0 +1,191 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
https://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
https://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.
|
|
@ -0,0 +1,32 @@
|
||||||
|
# platforms
|
||||||
|
|
||||||
|
A Go package for formatting, normalizing and matching container platforms.
|
||||||
|
|
||||||
|
This package is based on the Open Containers Image Spec definition of a [platform](https://github.com/opencontainers/image-spec/blob/main/specs-go/v1/descriptor.go#L52).
|
||||||
|
|
||||||
|
## Platform Specifier
|
||||||
|
|
||||||
|
While the OCI platform specifications provide a tool for components to
|
||||||
|
specify structured information, user input typically doesn't need the full
|
||||||
|
context and much can be inferred. To solve this problem, this package introduces
|
||||||
|
"specifiers". A specifier has the format
|
||||||
|
`<os>|<arch>|<os>/<arch>[/<variant>]`. The user can provide either the
|
||||||
|
operating system or the architecture or both.
|
||||||
|
|
||||||
|
An example of a common specifier is `linux/amd64`. If the host has a default
|
||||||
|
runtime that matches this, the user can simply provide the component that
|
||||||
|
matters. For example, if an image provides `amd64` and `arm64` support, the
|
||||||
|
operating system, `linux` can be inferred, so they only have to provide
|
||||||
|
`arm64` or `amd64`. Similar behavior is implemented for operating systems,
|
||||||
|
where the architecture may be known but a runtime may support images from
|
||||||
|
different operating systems.
|
||||||
|
|
||||||
|
## Project details
|
||||||
|
|
||||||
|
**platforms** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
|
||||||
|
As a containerd sub-project, you will find the:
|
||||||
|
* [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
|
||||||
|
* [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
|
||||||
|
* and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
|
||||||
|
|
||||||
|
information in our [`containerd/project`](https://github.com/containerd/project) repository.
|
|
@ -19,12 +19,12 @@ package platforms
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containerd/errdefs"
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ func getCPUInfo(pattern string) (info string, err error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("getCPUInfo for pattern %s: %w", pattern, errdefs.ErrNotFound)
|
return "", fmt.Errorf("getCPUInfo for pattern %s: %w", pattern, errNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCPUVariantFromArch get CPU variant from arch through a system call
|
// getCPUVariantFromArch get CPU variant from arch through a system call
|
||||||
|
@ -83,7 +83,7 @@ func getCPUVariantFromArch(arch string) (string, error) {
|
||||||
if arch == "aarch64" {
|
if arch == "aarch64" {
|
||||||
variant = "8"
|
variant = "8"
|
||||||
} else if arch[0:4] == "armv" && len(arch) >= 5 {
|
} else if arch[0:4] == "armv" && len(arch) >= 5 {
|
||||||
//Valid arch format is in form of armvXx
|
// Valid arch format is in form of armvXx
|
||||||
switch arch[3:5] {
|
switch arch[3:5] {
|
||||||
case "v8":
|
case "v8":
|
||||||
variant = "8"
|
variant = "8"
|
||||||
|
@ -101,7 +101,7 @@ func getCPUVariantFromArch(arch string) (string, error) {
|
||||||
variant = "unknown"
|
variant = "unknown"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return "", fmt.Errorf("getCPUVariantFromArch invalid arch: %s, %w", arch, errdefs.ErrInvalidArgument)
|
return "", fmt.Errorf("getCPUVariantFromArch invalid arch: %s, %w", arch, errInvalidArgument)
|
||||||
}
|
}
|
||||||
return variant, nil
|
return variant, nil
|
||||||
}
|
}
|
||||||
|
@ -112,11 +112,10 @@ func getCPUVariantFromArch(arch string) (string, error) {
|
||||||
// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
|
// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
|
||||||
// was not present.
|
// was not present.
|
||||||
func getCPUVariant() (string, error) {
|
func getCPUVariant() (string, error) {
|
||||||
|
|
||||||
variant, err := getCPUInfo("Cpu architecture")
|
variant, err := getCPUInfo("Cpu architecture")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errdefs.IsNotFound(err) {
|
if errors.Is(err, errNotFound) {
|
||||||
//Let's try getting CPU variant from machine architecture
|
// Let's try getting CPU variant from machine architecture
|
||||||
arch, err := getMachineArch()
|
arch, err := getMachineArch()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failure getting machine architecture: %v", err)
|
return "", fmt.Errorf("failure getting machine architecture: %v", err)
|
|
@ -21,8 +21,6 @@ package platforms
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/containerd/errdefs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getCPUVariant() (string, error) {
|
func getCPUVariant() (string, error) {
|
||||||
|
@ -49,10 +47,8 @@ func getCPUVariant() (string, error) {
|
||||||
default:
|
default:
|
||||||
variant = "unknown"
|
variant = "unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return "", fmt.Errorf("getCPUVariant for OS %s: %v", runtime.GOOS, errdefs.ErrNotImplemented)
|
return "", fmt.Errorf("getCPUVariant for OS %s: %v", runtime.GOOS, errNotImplemented)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return variant, nil
|
return variant, nil
|
|
@ -16,9 +16,11 @@
|
||||||
|
|
||||||
package platforms
|
package platforms
|
||||||
|
|
||||||
// DefaultString returns the default string specifier for the platform.
|
// DefaultString returns the default string specifier for the platform,
|
||||||
|
// with [PR#6](https://github.com/containerd/platforms/pull/6) the result
|
||||||
|
// may now also include the OSVersion from the provided platform specification.
|
||||||
func DefaultString() string {
|
func DefaultString() string {
|
||||||
return Format(DefaultSpec())
|
return FormatAll(DefaultSpec())
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultStrict returns strict form of Default.
|
// DefaultStrict returns strict form of Default.
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/osversion"
|
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
@ -52,29 +51,29 @@ func (m windowsmatcher) Match(p specs.Platform) bool {
|
||||||
|
|
||||||
if match && m.OS == "windows" {
|
if match && m.OS == "windows" {
|
||||||
// HPC containers do not have OS version filled
|
// HPC containers do not have OS version filled
|
||||||
if p.OSVersion == "" {
|
if m.OSVersion == "" || p.OSVersion == "" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
hostOsVersion := GetOsVersion(m.osVersionPrefix)
|
hostOsVersion := getOSVersion(m.osVersionPrefix)
|
||||||
ctrOsVersion := GetOsVersion(p.OSVersion)
|
ctrOsVersion := getOSVersion(p.OSVersion)
|
||||||
return osversion.CheckHostAndContainerCompat(hostOsVersion, ctrOsVersion)
|
return checkHostAndContainerCompat(hostOsVersion, ctrOsVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
return match
|
return match
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetOsVersion(osVersionPrefix string) osversion.OSVersion {
|
func getOSVersion(osVersionPrefix string) osVersion {
|
||||||
parts := strings.Split(osVersionPrefix, ".")
|
parts := strings.Split(osVersionPrefix, ".")
|
||||||
if len(parts) < 3 {
|
if len(parts) < 3 {
|
||||||
return osversion.OSVersion{}
|
return osVersion{}
|
||||||
}
|
}
|
||||||
|
|
||||||
majorVersion, _ := strconv.Atoi(parts[0])
|
majorVersion, _ := strconv.Atoi(parts[0])
|
||||||
minorVersion, _ := strconv.Atoi(parts[1])
|
minorVersion, _ := strconv.Atoi(parts[1])
|
||||||
buildNumber, _ := strconv.Atoi(parts[2])
|
buildNumber, _ := strconv.Atoi(parts[2])
|
||||||
|
|
||||||
return osversion.OSVersion{
|
return osVersion{
|
||||||
MajorVersion: uint8(majorVersion),
|
MajorVersion: uint8(majorVersion),
|
||||||
MinorVersion: uint8(minorVersion),
|
MinorVersion: uint8(minorVersion),
|
||||||
Build: uint16(buildNumber),
|
Build: uint16(buildNumber),
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
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 platforms
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
// These errors mirror the errors defined in [github.com/containerd/containerd/errdefs],
|
||||||
|
// however, they are not exported as they are not expected to be used as sentinel
|
||||||
|
// errors by consumers of this package.
|
||||||
|
//
|
||||||
|
//nolint:unused // not all errors are used on all platforms.
|
||||||
|
var (
|
||||||
|
errNotFound = errors.New("not found")
|
||||||
|
errInvalidArgument = errors.New("invalid argument")
|
||||||
|
errNotImplemented = errors.New("not implemented")
|
||||||
|
)
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
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 platforms
|
||||||
|
|
||||||
|
// osVersion is a wrapper for Windows version information
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
|
||||||
|
type osVersion struct {
|
||||||
|
Version uint32
|
||||||
|
MajorVersion uint8
|
||||||
|
MinorVersion uint8
|
||||||
|
Build uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows Client and Server build numbers.
|
||||||
|
//
|
||||||
|
// See:
|
||||||
|
// https://learn.microsoft.com/en-us/windows/release-health/release-information
|
||||||
|
// https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info
|
||||||
|
// https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information
|
||||||
|
const (
|
||||||
|
// rs5 (version 1809, codename "Redstone 5") corresponds to Windows Server
|
||||||
|
// 2019 (ltsc2019), and Windows 10 (October 2018 Update).
|
||||||
|
rs5 = 17763
|
||||||
|
|
||||||
|
// v21H2Server corresponds to Windows Server 2022 (ltsc2022).
|
||||||
|
v21H2Server = 20348
|
||||||
|
|
||||||
|
// v22H2Win11 corresponds to Windows 11 (2022 Update).
|
||||||
|
v22H2Win11 = 22621
|
||||||
|
)
|
||||||
|
|
||||||
|
// List of stable ABI compliant ltsc releases
|
||||||
|
// Note: List must be sorted in ascending order
|
||||||
|
var compatLTSCReleases = []uint16{
|
||||||
|
v21H2Server,
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckHostAndContainerCompat checks if given host and container
|
||||||
|
// OS versions are compatible.
|
||||||
|
// It includes support for stable ABI compliant versions as well.
|
||||||
|
// Every release after WS 2022 will support the previous ltsc
|
||||||
|
// container image. Stable ABI is in preview mode for windows 11 client.
|
||||||
|
// Refer: https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2022%2Cwindows-10#windows-server-host-os-compatibility
|
||||||
|
func checkHostAndContainerCompat(host, ctr osVersion) bool {
|
||||||
|
// check major minor versions of host and guest
|
||||||
|
if host.MajorVersion != ctr.MajorVersion ||
|
||||||
|
host.MinorVersion != ctr.MinorVersion {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If host is < WS 2022, exact version match is required
|
||||||
|
if host.Build < v21H2Server {
|
||||||
|
return host.Build == ctr.Build
|
||||||
|
}
|
||||||
|
|
||||||
|
var supportedLtscRelease uint16
|
||||||
|
for i := len(compatLTSCReleases) - 1; i >= 0; i-- {
|
||||||
|
if host.Build >= compatLTSCReleases[i] {
|
||||||
|
supportedLtscRelease = compatLTSCReleases[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctr.Build >= supportedLtscRelease && ctr.Build <= host.Build
|
||||||
|
}
|
|
@ -102,6 +102,9 @@
|
||||||
// unless it is explicitly provided. This is treated as equivalent to armhf. A
|
// unless it is explicitly provided. This is treated as equivalent to armhf. A
|
||||||
// previous architecture, armel, will be normalized to arm/v6.
|
// previous architecture, armel, will be normalized to arm/v6.
|
||||||
//
|
//
|
||||||
|
// Similarly, the most common arm64 version v8, and most common amd64 version v1
|
||||||
|
// are represented without the variant.
|
||||||
|
//
|
||||||
// While these normalizations are provided, their support on arm platforms has
|
// While these normalizations are provided, their support on arm platforms has
|
||||||
// not yet been fully implemented and tested.
|
// not yet been fully implemented and tested.
|
||||||
package platforms
|
package platforms
|
||||||
|
@ -115,14 +118,15 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
|
||||||
"github.com/containerd/errdefs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
specifierRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
|
specifierRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
|
||||||
|
osAndVersionRe = regexp.MustCompile(`^([A-Za-z0-9_-]+)(?:\(([A-Za-z0-9_.-]*)\))?$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const osAndVersionFormat = "%s(%s)"
|
||||||
|
|
||||||
// Platform is a type alias for convenience, so there is no need to import image-spec package everywhere.
|
// Platform is a type alias for convenience, so there is no need to import image-spec package everywhere.
|
||||||
type Platform = specs.Platform
|
type Platform = specs.Platform
|
||||||
|
|
||||||
|
@ -155,40 +159,68 @@ func (m *matcher) Match(platform specs.Platform) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *matcher) String() string {
|
func (m *matcher) String() string {
|
||||||
return Format(m.Platform)
|
return FormatAll(m.Platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseAll parses a list of platform specifiers into a list of platform.
|
||||||
|
func ParseAll(specifiers []string) ([]specs.Platform, error) {
|
||||||
|
platforms := make([]specs.Platform, len(specifiers))
|
||||||
|
for i, s := range specifiers {
|
||||||
|
p, err := Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid platform %s: %w", s, err)
|
||||||
|
}
|
||||||
|
platforms[i] = p
|
||||||
|
}
|
||||||
|
return platforms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses the platform specifier syntax into a platform declaration.
|
// Parse parses the platform specifier syntax into a platform declaration.
|
||||||
//
|
//
|
||||||
// Platform specifiers are in the format `<os>|<arch>|<os>/<arch>[/<variant>]`.
|
// Platform specifiers are in the format `<os>[(<OSVersion>)]|<arch>|<os>[(<OSVersion>)]/<arch>[/<variant>]`.
|
||||||
// The minimum required information for a platform specifier is the operating
|
// The minimum required information for a platform specifier is the operating
|
||||||
// system or architecture. If there is only a single string (no slashes), the
|
// system or architecture. The OSVersion can be part of the OS like `windows(10.0.17763)`
|
||||||
|
// When an OSVersion is specified, then specs.Platform.OSVersion is populated with that value,
|
||||||
|
// and an empty string otherwise.
|
||||||
|
// If there is only a single string (no slashes), the
|
||||||
// value will be matched against the known set of operating systems, then fall
|
// value will be matched against the known set of operating systems, then fall
|
||||||
// back to the known set of architectures. The missing component will be
|
// back to the known set of architectures. The missing component will be
|
||||||
// inferred based on the local environment.
|
// inferred based on the local environment.
|
||||||
func Parse(specifier string) (specs.Platform, error) {
|
func Parse(specifier string) (specs.Platform, error) {
|
||||||
if strings.Contains(specifier, "*") {
|
if strings.Contains(specifier, "*") {
|
||||||
// TODO(stevvooe): need to work out exact wildcard handling
|
// TODO(stevvooe): need to work out exact wildcard handling
|
||||||
return specs.Platform{}, fmt.Errorf("%q: wildcards not yet supported: %w", specifier, errdefs.ErrInvalidArgument)
|
return specs.Platform{}, fmt.Errorf("%q: wildcards not yet supported: %w", specifier, errInvalidArgument)
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.Split(specifier, "/")
|
// Limit to 4 elements to prevent unbounded split
|
||||||
|
parts := strings.SplitN(specifier, "/", 4)
|
||||||
|
|
||||||
for _, part := range parts {
|
var p specs.Platform
|
||||||
if !specifierRe.MatchString(part) {
|
for i, part := range parts {
|
||||||
return specs.Platform{}, fmt.Errorf("%q is an invalid component of %q: platform specifier component must match %q: %w", part, specifier, specifierRe.String(), errdefs.ErrInvalidArgument)
|
if i == 0 {
|
||||||
|
// First element is <os>[(<OSVersion>)]
|
||||||
|
osVer := osAndVersionRe.FindStringSubmatch(part)
|
||||||
|
if osVer == nil {
|
||||||
|
return specs.Platform{}, fmt.Errorf("%q is an invalid OS component of %q: OSAndVersion specifier component must match %q: %w", part, specifier, osAndVersionRe.String(), errInvalidArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.OS = normalizeOS(osVer[1])
|
||||||
|
p.OSVersion = osVer[2]
|
||||||
|
} else {
|
||||||
|
if !specifierRe.MatchString(part) {
|
||||||
|
return specs.Platform{}, fmt.Errorf("%q is an invalid component of %q: platform specifier component must match %q: %w", part, specifier, specifierRe.String(), errInvalidArgument)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var p specs.Platform
|
|
||||||
switch len(parts) {
|
switch len(parts) {
|
||||||
case 1:
|
case 1:
|
||||||
// in this case, we will test that the value might be an OS, then look
|
// in this case, we will test that the value might be an OS (with or
|
||||||
// it up. If it is not known, we'll treat it as an architecture. Since
|
// without the optional OSVersion specified) and look it up.
|
||||||
|
// If it is not known, we'll treat it as an architecture. Since
|
||||||
// we have very little information about the platform here, we are
|
// we have very little information about the platform here, we are
|
||||||
// going to be a little more strict if we don't know about the argument
|
// going to be a little more strict if we don't know about the argument
|
||||||
// value.
|
// value.
|
||||||
p.OS = normalizeOS(parts[0])
|
|
||||||
if isKnownOS(p.OS) {
|
if isKnownOS(p.OS) {
|
||||||
// picks a default architecture
|
// picks a default architecture
|
||||||
p.Architecture = runtime.GOARCH
|
p.Architecture = runtime.GOARCH
|
||||||
|
@ -196,10 +228,6 @@ func Parse(specifier string) (specs.Platform, error) {
|
||||||
p.Variant = cpuVariant()
|
p.Variant = cpuVariant()
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.OS == "windows" {
|
|
||||||
p.OSVersion = GetWindowsOsVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,37 +240,27 @@ func Parse(specifier string) (specs.Platform, error) {
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return specs.Platform{}, fmt.Errorf("%q: unknown operating system or architecture: %w", specifier, errdefs.ErrInvalidArgument)
|
return specs.Platform{}, fmt.Errorf("%q: unknown operating system or architecture: %w", specifier, errInvalidArgument)
|
||||||
case 2:
|
case 2:
|
||||||
// In this case, we treat as a regular os/arch pair. We don't care
|
// In this case, we treat as a regular OS[(OSVersion)]/arch pair. We don't care
|
||||||
// about whether or not we know of the platform.
|
// about whether or not we know of the platform.
|
||||||
p.OS = normalizeOS(parts[0])
|
|
||||||
p.Architecture, p.Variant = normalizeArch(parts[1], "")
|
p.Architecture, p.Variant = normalizeArch(parts[1], "")
|
||||||
if p.Architecture == "arm" && p.Variant == "v7" {
|
if p.Architecture == "arm" && p.Variant == "v7" {
|
||||||
p.Variant = ""
|
p.Variant = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.OS == "windows" {
|
|
||||||
p.OSVersion = GetWindowsOsVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
case 3:
|
case 3:
|
||||||
// we have a fully specified variant, this is rare
|
// we have a fully specified variant, this is rare
|
||||||
p.OS = normalizeOS(parts[0])
|
|
||||||
p.Architecture, p.Variant = normalizeArch(parts[1], parts[2])
|
p.Architecture, p.Variant = normalizeArch(parts[1], parts[2])
|
||||||
if p.Architecture == "arm64" && p.Variant == "" {
|
if p.Architecture == "arm64" && p.Variant == "" {
|
||||||
p.Variant = "v8"
|
p.Variant = "v8"
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.OS == "windows" {
|
|
||||||
p.OSVersion = GetWindowsOsVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return specs.Platform{}, fmt.Errorf("%q: cannot parse platform specifier: %w", specifier, errdefs.ErrInvalidArgument)
|
return specs.Platform{}, fmt.Errorf("%q: cannot parse platform specifier: %w", specifier, errInvalidArgument)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustParse is like Parses but panics if the specifier cannot be parsed.
|
// MustParse is like Parses but panics if the specifier cannot be parsed.
|
||||||
|
@ -264,6 +282,20 @@ func Format(platform specs.Platform) string {
|
||||||
return path.Join(platform.OS, platform.Architecture, platform.Variant)
|
return path.Join(platform.OS, platform.Architecture, platform.Variant)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FormatAll returns a string specifier that also includes the OSVersion from the
|
||||||
|
// provided platform specification.
|
||||||
|
func FormatAll(platform specs.Platform) string {
|
||||||
|
if platform.OS == "" {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
if platform.OSVersion != "" {
|
||||||
|
OSAndVersion := fmt.Sprintf(osAndVersionFormat, platform.OS, platform.OSVersion)
|
||||||
|
return path.Join(OSAndVersion, platform.Architecture, platform.Variant)
|
||||||
|
}
|
||||||
|
return path.Join(platform.OS, platform.Architecture, platform.Variant)
|
||||||
|
}
|
||||||
|
|
||||||
// Normalize validates and translate the platform to the canonical value.
|
// Normalize validates and translate the platform to the canonical value.
|
||||||
//
|
//
|
||||||
// For example, if "Aarch64" is encountered, we change it to "arm64" or if
|
// For example, if "Aarch64" is encountered, we change it to "arm64" or if
|
|
@ -28,7 +28,3 @@ func newDefaultMatcher(platform specs.Platform) Matcher {
|
||||||
Platform: Normalize(platform),
|
Platform: Normalize(platform),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetWindowsOsVersion() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
|
@ -17,10 +17,7 @@
|
||||||
package platforms
|
package platforms
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewMatcher returns a Windows matcher that will match on osVersionPrefix if
|
// NewMatcher returns a Windows matcher that will match on osVersionPrefix if
|
||||||
|
@ -35,8 +32,3 @@ func newDefaultMatcher(platform specs.Platform) Matcher {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetWindowsOsVersion() string {
|
|
||||||
major, minor, build := windows.RtlGetNtVersionNumbers()
|
|
||||||
return fmt.Sprintf("%d.%d.%d", major, minor, build)
|
|
||||||
}
|
|
|
@ -1,66 +1,284 @@
|
||||||
# This file lists all individuals having contributed content to the repository.
|
# 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 L. Xu <likexu@harmonycloud.cn>
|
||||||
Aaron Lehmann <aaron.lehmann@docker.com>
|
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>
|
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>
|
Alexander Morozov <lk4d4@docker.com>
|
||||||
|
Alexis Murzeau <amubtdx@gmail.com>
|
||||||
Alice Frosi <afrosi@de.ibm.com>
|
Alice Frosi <afrosi@de.ibm.com>
|
||||||
Allen Sun <allen.sun@daocloud.io>
|
Allen Sun <allen.sun@daocloud.io>
|
||||||
|
Amen Belayneh <amenbelayneh@gmail.com>
|
||||||
|
Anca Iordache <anca.iordache@docker.com>
|
||||||
Anda Xu <anda.xu@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>
|
Anthony Sottile <asottile@umich.edu>
|
||||||
|
Anurag Goel <anurag@render.com>
|
||||||
|
Anusha Ragunathan <anusha@docker.com>
|
||||||
Arnaud Bailly <arnaud.oqube@gmail.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>
|
Bin Liu <liubin0329@gmail.com>
|
||||||
|
Brandon Mitchell <git@bmitch.net>
|
||||||
Brian Goff <cpuguy83@gmail.com>
|
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>
|
Daniel Nephin <dnephin@gmail.com>
|
||||||
|
Darren Shepherd <darren@rancher.com>
|
||||||
Dave Chen <dave.chen@arm.com>
|
Dave Chen <dave.chen@arm.com>
|
||||||
|
Dave Henderson <dhenderson@gmail.com>
|
||||||
|
Dave Tucker <dt@docker.com>
|
||||||
David Calavera <david.calavera@gmail.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>
|
Dennis Chen <dennis.chen@arm.com>
|
||||||
|
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
||||||
Derek McGowan <derek@mcgstyle.net>
|
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>
|
Doug Davis <dug@us.ibm.com>
|
||||||
Edgar Lee <edgarl@netflix.com>
|
Edgar Lee <edgarhinshunlee@gmail.com>
|
||||||
Eli Uriegas <eli.uriegas@docker.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>
|
f0 <f0@users.noreply.github.com>
|
||||||
Fernando Miguel <github@FernandoMiguel.net>
|
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>
|
Hao Hu <hao.hu.fr@gmail.com>
|
||||||
|
Hector S <hfsam88@gmail.com>
|
||||||
Helen Xie <chenjg@harmonycloud.cn>
|
Helen Xie <chenjg@harmonycloud.cn>
|
||||||
Himanshu Pandey <hpandey@pivotal.io>
|
Himanshu Pandey <hpandey@pivotal.io>
|
||||||
Hiromu Nakamura <abctail30@gmail.com>
|
Hiromu Nakamura <abctail30@gmail.com>
|
||||||
|
HowJMay <vulxj0j8j8@gmail.com>
|
||||||
|
Hugo Santos <hugo@namespacelabs.com>
|
||||||
Ian Campbell <ijc@docker.com>
|
Ian Campbell <ijc@docker.com>
|
||||||
|
Ilya Dmitrichenko <errordeveloper@gmail.com>
|
||||||
Iskander (Alex) Sharipov <quasilyte@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>
|
Jean-Pierre Huynh <jean-pierre.huynh@ounet.fr>
|
||||||
|
Jeffrey Huang <jeffreyhuang23@gmail.com>
|
||||||
|
Jesse Rittner <rittneje@gmail.com>
|
||||||
Jessica Frazelle <acidburn@microsoft.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 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>
|
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>
|
Justas Brazauskas <brazauskasjustas@gmail.com>
|
||||||
|
Justin Chadwell <me@jedevc.com>
|
||||||
Justin Cormack <justin.cormack@docker.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>
|
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
|
||||||
|
Kyle <Kylemit@gmail.com>
|
||||||
|
l00397676 <lujingxiao@huawei.com>
|
||||||
Lajos Papp <lalyos@yahoo.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>
|
Matt Rickard <mrick@google.com>
|
||||||
|
Maxime Lagresle <maxime@angel.co>
|
||||||
Michael Crosby <crosbymichael@gmail.com>
|
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>
|
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>
|
Nao YONASHIRO <yonashiro@r.recruit.co.jp>
|
||||||
Natasha Jarus <linuxmercedes@gmail.com>
|
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>
|
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>
|
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>
|
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>
|
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>
|
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>
|
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>
|
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>
|
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 Leonard <thomas.leonard@docker.com>
|
||||||
|
Thomas Riccardi <riccardi@systran.fr>
|
||||||
Thomas Shaw <tomwillfixit@users.noreply.github.com>
|
Thomas Shaw <tomwillfixit@users.noreply.github.com>
|
||||||
|
Tianon Gravi <admwiggin@gmail.com>
|
||||||
Tibor Vass <tibor@docker.com>
|
Tibor Vass <tibor@docker.com>
|
||||||
Tiffany Jernigan <tiffany.f.j@gmail.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>
|
Tino Rusch <tino.rusch@gmail.com>
|
||||||
Tobias Klauser <tklauser@distanz.ch>
|
Tobias Klauser <tklauser@distanz.ch>
|
||||||
Tomas Tomecek <ttomecek@redhat.com>
|
Tomas Tomecek <ttomecek@redhat.com>
|
||||||
|
Tomasz Kopczynski <tomek@kopczynski.net.pl>
|
||||||
Tomohiro Kusumoto <zabio1192@gmail.com>
|
Tomohiro Kusumoto <zabio1192@gmail.com>
|
||||||
|
Troels Liebe Bentsen <tlb@nversion.dk>
|
||||||
Tõnis Tiigi <tonistiigi@gmail.com>
|
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>
|
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 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>
|
Yong Tang <yong.tang.github@outlook.com>
|
||||||
Yuichiro Kaneko <spiketeika@gmail.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>
|
Ziv Tsarfati <digger18@gmail.com>
|
||||||
|
岁丰 <genglu.gl@antfin.com>
|
||||||
|
沈陵 <shenling.yyb@alibaba-inc.com>
|
||||||
郑泽宇 <perhapszzy@sina.com>
|
郑泽宇 <perhapszzy@sina.com>
|
||||||
|
|
|
@ -13,12 +13,14 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
keySyntax = "syntax"
|
keySyntax = "syntax"
|
||||||
|
keyCheck = "check"
|
||||||
keyEscape = "escape"
|
keyEscape = "escape"
|
||||||
)
|
)
|
||||||
|
|
||||||
var validDirectives = map[string]struct{}{
|
var validDirectives = map[string]struct{}{
|
||||||
keySyntax: {},
|
keySyntax: {},
|
||||||
keyEscape: {},
|
keyEscape: {},
|
||||||
|
keyCheck: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
type Directive struct {
|
type Directive struct {
|
||||||
|
@ -110,6 +112,10 @@ func (d *DirectiveParser) ParseAll(data []byte) ([]*Directive, error) {
|
||||||
// This allows for a flexible range of input formats, and appropriate syntax
|
// This allows for a flexible range of input formats, and appropriate syntax
|
||||||
// selection.
|
// selection.
|
||||||
func DetectSyntax(dt []byte) (string, string, []Range, bool) {
|
func DetectSyntax(dt []byte) (string, string, []Range, bool) {
|
||||||
|
return ParseDirective(keySyntax, dt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseDirective(key string, dt []byte) (string, string, []Range, bool) {
|
||||||
dt, hadShebang, err := discardShebang(dt)
|
dt, hadShebang, err := discardShebang(dt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", nil, false
|
return "", "", nil, false
|
||||||
|
@ -119,42 +125,38 @@ func DetectSyntax(dt []byte) (string, string, []Range, bool) {
|
||||||
line++
|
line++
|
||||||
}
|
}
|
||||||
|
|
||||||
// use default directive parser, and search for #syntax=
|
// use default directive parser, and search for #key=
|
||||||
directiveParser := DirectiveParser{line: line}
|
directiveParser := DirectiveParser{line: line}
|
||||||
if syntax, cmdline, loc, ok := detectSyntaxFromParser(dt, directiveParser); ok {
|
if syntax, cmdline, loc, ok := detectDirectiveFromParser(key, dt, directiveParser); ok {
|
||||||
return syntax, cmdline, loc, true
|
return syntax, cmdline, loc, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// use directive with different comment prefix, and search for //syntax=
|
// use directive with different comment prefix, and search for //key=
|
||||||
directiveParser = DirectiveParser{line: line}
|
directiveParser = DirectiveParser{line: line}
|
||||||
directiveParser.setComment("//")
|
directiveParser.setComment("//")
|
||||||
if syntax, cmdline, loc, ok := detectSyntaxFromParser(dt, directiveParser); ok {
|
if syntax, cmdline, loc, ok := detectDirectiveFromParser(key, dt, directiveParser); ok {
|
||||||
return syntax, cmdline, loc, true
|
return syntax, cmdline, loc, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// search for possible json directives
|
// use json directive, and search for { "key": "..." }
|
||||||
var directive struct {
|
jsonDirective := map[string]string{}
|
||||||
Syntax string `json:"syntax"`
|
if err := json.Unmarshal(dt, &jsonDirective); err == nil {
|
||||||
}
|
if v, ok := jsonDirective[key]; ok {
|
||||||
if err := json.Unmarshal(dt, &directive); err == nil {
|
|
||||||
if directive.Syntax != "" {
|
|
||||||
loc := []Range{{
|
loc := []Range{{
|
||||||
Start: Position{Line: line},
|
Start: Position{Line: line},
|
||||||
End: Position{Line: line},
|
End: Position{Line: line},
|
||||||
}}
|
}}
|
||||||
return directive.Syntax, directive.Syntax, loc, true
|
return v, v, loc, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", "", nil, false
|
return "", "", nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func detectSyntaxFromParser(dt []byte, parser DirectiveParser) (string, string, []Range, bool) {
|
func detectDirectiveFromParser(key string, dt []byte, parser DirectiveParser) (string, string, []Range, bool) {
|
||||||
directives, _ := parser.ParseAll(dt)
|
directives, _ := parser.ParseAll(dt)
|
||||||
for _, d := range directives {
|
for _, d := range directives {
|
||||||
// check for syntax directive before erroring out, since the error
|
if d.Name == key {
|
||||||
// might have occurred *after* the syntax directive
|
|
||||||
if d.Name == keySyntax {
|
|
||||||
p, _, _ := strings.Cut(d.Value, " ")
|
p, _, _ := strings.Cut(d.Value, " ")
|
||||||
return p, d.Value, d.Location, true
|
return p, d.Value, d.Location, true
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
// ErrorLocation gives a location in source code that caused the error
|
// ErrorLocation gives a location in source code that caused the error
|
||||||
type ErrorLocation struct {
|
type ErrorLocation struct {
|
||||||
Location []Range
|
Locations [][]Range
|
||||||
error
|
error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,11 +39,12 @@ func WithLocation(err error, location []Range) error {
|
||||||
}
|
}
|
||||||
var el *ErrorLocation
|
var el *ErrorLocation
|
||||||
if errors.As(err, &el) {
|
if errors.As(err, &el) {
|
||||||
|
el.Locations = append(el.Locations, location)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return stack.Enable(&ErrorLocation{
|
return stack.Enable(&ErrorLocation{
|
||||||
error: err,
|
error: err,
|
||||||
Location: location,
|
Locations: [][]Range{location},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errDockerfileNotStringArray = errors.New("when using JSON array syntax, arrays must be comprised of strings only")
|
errDockerfileNotStringArray = errors.New("when using JSON array syntax, arrays must be comprised of strings only")
|
||||||
|
errDockerfileNotJSONArray = errors.New("not a JSON array")
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -58,11 +59,11 @@ func parseWords(rest string, d *directives) []string {
|
||||||
|
|
||||||
words := []string{}
|
words := []string{}
|
||||||
phase := inSpaces
|
phase := inSpaces
|
||||||
word := ""
|
|
||||||
quote := '\000'
|
quote := '\000'
|
||||||
blankOK := false
|
blankOK := false
|
||||||
var ch rune
|
var ch rune
|
||||||
var chWidth int
|
var chWidth int
|
||||||
|
var sbuilder strings.Builder
|
||||||
|
|
||||||
for pos := 0; pos <= len(rest); pos += chWidth {
|
for pos := 0; pos <= len(rest); pos += chWidth {
|
||||||
if pos != len(rest) {
|
if pos != len(rest) {
|
||||||
|
@ -79,18 +80,18 @@ func parseWords(rest string, d *directives) []string {
|
||||||
phase = inWord // found it, fall through
|
phase = inWord // found it, fall through
|
||||||
}
|
}
|
||||||
if (phase == inWord || phase == inQuote) && (pos == len(rest)) {
|
if (phase == inWord || phase == inQuote) && (pos == len(rest)) {
|
||||||
if blankOK || len(word) > 0 {
|
if blankOK || sbuilder.Len() > 0 {
|
||||||
words = append(words, word)
|
words = append(words, sbuilder.String())
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if phase == inWord {
|
if phase == inWord {
|
||||||
if unicode.IsSpace(ch) {
|
if unicode.IsSpace(ch) {
|
||||||
phase = inSpaces
|
phase = inSpaces
|
||||||
if blankOK || len(word) > 0 {
|
if blankOK || sbuilder.Len() > 0 {
|
||||||
words = append(words, word)
|
words = append(words, sbuilder.String())
|
||||||
}
|
}
|
||||||
word = ""
|
sbuilder.Reset()
|
||||||
blankOK = false
|
blankOK = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -106,11 +107,11 @@ func parseWords(rest string, d *directives) []string {
|
||||||
// If we're not quoted and we see an escape token, then always just
|
// If we're not quoted and we see an escape token, then always just
|
||||||
// add the escape token plus the char to the word, even if the char
|
// add the escape token plus the char to the word, even if the char
|
||||||
// is a quote.
|
// is a quote.
|
||||||
word += string(ch)
|
sbuilder.WriteRune(ch)
|
||||||
pos += chWidth
|
pos += chWidth
|
||||||
ch, chWidth = utf8.DecodeRuneInString(rest[pos:])
|
ch, chWidth = utf8.DecodeRuneInString(rest[pos:])
|
||||||
}
|
}
|
||||||
word += string(ch)
|
sbuilder.WriteRune(ch)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if phase == inQuote {
|
if phase == inQuote {
|
||||||
|
@ -124,10 +125,10 @@ func parseWords(rest string, d *directives) []string {
|
||||||
continue // just skip the escape token at end
|
continue // just skip the escape token at end
|
||||||
}
|
}
|
||||||
pos += chWidth
|
pos += chWidth
|
||||||
word += string(ch)
|
sbuilder.WriteRune(ch)
|
||||||
ch, chWidth = utf8.DecodeRuneInString(rest[pos:])
|
ch, chWidth = utf8.DecodeRuneInString(rest[pos:])
|
||||||
}
|
}
|
||||||
word += string(ch)
|
sbuilder.WriteRune(ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +155,7 @@ func parseNameVal(rest string, key string, d *directives) (*Node, error) {
|
||||||
if len(parts) < 2 {
|
if len(parts) < 2 {
|
||||||
return nil, errors.Errorf("%s must have two arguments", key)
|
return nil, errors.Errorf("%s must have two arguments", key)
|
||||||
}
|
}
|
||||||
return newKeyValueNode(parts[0], parts[1]), nil
|
return newKeyValueNode(parts[0], parts[1], ""), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var rootNode *Node
|
var rootNode *Node
|
||||||
|
@ -165,17 +166,20 @@ func parseNameVal(rest string, key string, d *directives) (*Node, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.SplitN(word, "=", 2)
|
parts := strings.SplitN(word, "=", 2)
|
||||||
node := newKeyValueNode(parts[0], parts[1])
|
node := newKeyValueNode(parts[0], parts[1], "=")
|
||||||
rootNode, prevNode = appendKeyValueNode(node, rootNode, prevNode)
|
rootNode, prevNode = appendKeyValueNode(node, rootNode, prevNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
return rootNode, nil
|
return rootNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newKeyValueNode(key, value string) *Node {
|
func newKeyValueNode(key, value, sep string) *Node {
|
||||||
return &Node{
|
return &Node{
|
||||||
Value: key,
|
Value: key,
|
||||||
Next: &Node{Value: value},
|
Next: &Node{
|
||||||
|
Value: value,
|
||||||
|
Next: &Node{Value: sep},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +191,9 @@ func appendKeyValueNode(node, rootNode, prevNode *Node) (*Node, *Node) {
|
||||||
prevNode.Next = node
|
prevNode.Next = node
|
||||||
}
|
}
|
||||||
|
|
||||||
prevNode = node.Next
|
for prevNode = node.Next; prevNode.Next != nil; {
|
||||||
|
prevNode = prevNode.Next
|
||||||
|
}
|
||||||
return rootNode, prevNode
|
return rootNode, prevNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,14 +275,14 @@ func parseString(rest string, d *directives) (*Node, map[string]bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseJSON converts JSON arrays to an AST.
|
// parseJSON converts JSON arrays to an AST.
|
||||||
func parseJSON(rest string, d *directives) (*Node, map[string]bool, error) {
|
func parseJSON(rest string) (*Node, map[string]bool, error) {
|
||||||
rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
|
rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
|
||||||
if !strings.HasPrefix(rest, "[") {
|
if !strings.HasPrefix(rest, "[") {
|
||||||
return nil, nil, errors.Errorf("Error parsing %q as a JSON array", rest)
|
return nil, nil, errDockerfileNotJSONArray
|
||||||
}
|
}
|
||||||
|
|
||||||
var myJSON []interface{}
|
var myJSON []interface{}
|
||||||
if err := json.NewDecoder(strings.NewReader(rest)).Decode(&myJSON); err != nil {
|
if err := json.Unmarshal([]byte(rest), &myJSON); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +313,7 @@ func parseMaybeJSON(rest string, d *directives) (*Node, map[string]bool, error)
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
node, attrs, err := parseJSON(rest, d)
|
node, attrs, err := parseJSON(rest)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return node, attrs, nil
|
return node, attrs, nil
|
||||||
|
@ -325,7 +331,7 @@ func parseMaybeJSON(rest string, d *directives) (*Node, map[string]bool, error)
|
||||||
// so, passes to parseJSON; if not, attempts to parse it as a whitespace
|
// so, passes to parseJSON; if not, attempts to parse it as a whitespace
|
||||||
// delimited string.
|
// delimited string.
|
||||||
func parseMaybeJSONToList(rest string, d *directives) (*Node, map[string]bool, error) {
|
func parseMaybeJSONToList(rest string, d *directives) (*Node, map[string]bool, error) {
|
||||||
node, attrs, err := parseJSON(rest, d)
|
node, attrs, err := parseJSON(rest)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return node, attrs, nil
|
return node, attrs, nil
|
||||||
|
|
|
@ -114,7 +114,6 @@ type Heredoc struct {
|
||||||
var (
|
var (
|
||||||
dispatch map[string]func(string, *directives) (*Node, map[string]bool, error)
|
dispatch map[string]func(string, *directives) (*Node, map[string]bool, error)
|
||||||
reWhitespace = regexp.MustCompile(`[\t\v\f\r ]+`)
|
reWhitespace = regexp.MustCompile(`[\t\v\f\r ]+`)
|
||||||
reComment = regexp.MustCompile(`^#.*$`)
|
|
||||||
reHeredoc = regexp.MustCompile(`^(\d*)<<(-?)([^<]*)$`)
|
reHeredoc = regexp.MustCompile(`^(\d*)<<(-?)([^<]*)$`)
|
||||||
reLeadingTabs = regexp.MustCompile(`(?m)^\t+`)
|
reLeadingTabs = regexp.MustCompile(`(?m)^\t+`)
|
||||||
)
|
)
|
||||||
|
@ -169,8 +168,8 @@ func (d *directives) setEscapeToken(s string) error {
|
||||||
// possibleParserDirective looks for parser directives, eg '# escapeToken=<char>'.
|
// possibleParserDirective looks for parser directives, eg '# escapeToken=<char>'.
|
||||||
// Parser directives must precede any builder instruction or other comments,
|
// Parser directives must precede any builder instruction or other comments,
|
||||||
// and cannot be repeated.
|
// and cannot be repeated.
|
||||||
func (d *directives) possibleParserDirective(line string) error {
|
func (d *directives) possibleParserDirective(line []byte) error {
|
||||||
directive, err := d.parser.ParseLine([]byte(line))
|
directive, err := d.parser.ParseLine(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -284,6 +283,7 @@ func Parse(rwc io.Reader) (*Result, error) {
|
||||||
scanner.Split(scanLines)
|
scanner.Split(scanLines)
|
||||||
warnings := []Warning{}
|
warnings := []Warning{}
|
||||||
var comments []string
|
var comments []string
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
|
@ -307,10 +307,12 @@ func Parse(rwc io.Reader) (*Result, error) {
|
||||||
currentLine++
|
currentLine++
|
||||||
|
|
||||||
startLine := currentLine
|
startLine := currentLine
|
||||||
line, isEndOfLine := trimContinuationCharacter(string(bytesRead), d)
|
bytesRead, isEndOfLine := trimContinuationCharacter(bytesRead, d)
|
||||||
if isEndOfLine && line == "" {
|
if isEndOfLine && len(bytesRead) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
buf.Reset()
|
||||||
|
buf.Write(bytesRead)
|
||||||
|
|
||||||
var hasEmptyContinuationLine bool
|
var hasEmptyContinuationLine bool
|
||||||
for !isEndOfLine && scanner.Scan() {
|
for !isEndOfLine && scanner.Scan() {
|
||||||
|
@ -329,16 +331,17 @@ func Parse(rwc io.Reader) (*Result, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
continuationLine := string(bytesRead)
|
bytesRead, isEndOfLine = trimContinuationCharacter(bytesRead, d)
|
||||||
continuationLine, isEndOfLine = trimContinuationCharacter(continuationLine, d)
|
buf.Write(bytesRead)
|
||||||
line += continuationLine
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line := buf.String()
|
||||||
|
|
||||||
if hasEmptyContinuationLine {
|
if hasEmptyContinuationLine {
|
||||||
warnings = append(warnings, Warning{
|
warnings = append(warnings, Warning{
|
||||||
Short: "Empty continuation line found in: " + line,
|
Short: "Empty continuation line found in: " + line,
|
||||||
Detail: [][]byte{[]byte("Empty continuation lines will become errors in a future release")},
|
Detail: [][]byte{[]byte("Empty continuation lines will become errors in a future release")},
|
||||||
URL: "https://github.com/moby/moby/pull/33719",
|
URL: "https://docs.docker.com/go/dockerfile/rule/no-empty-continuation/",
|
||||||
Location: &Range{Start: Position{Line: currentLine}, End: Position{Line: currentLine}},
|
Location: &Range{Start: Position{Line: currentLine}, End: Position{Line: currentLine}},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -348,7 +351,7 @@ func Parse(rwc io.Reader) (*Result, error) {
|
||||||
return nil, withLocation(err, startLine, currentLine)
|
return nil, withLocation(err, startLine, currentLine)
|
||||||
}
|
}
|
||||||
|
|
||||||
if child.canContainHeredoc() {
|
if child.canContainHeredoc() && strings.Contains(line, "<<") {
|
||||||
heredocs, err := heredocsFromLine(line)
|
heredocs, err := heredocsFromLine(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, withLocation(err, startLine, currentLine)
|
return nil, withLocation(err, startLine, currentLine)
|
||||||
|
@ -415,7 +418,7 @@ func heredocFromMatch(match []string) (*Heredoc, error) {
|
||||||
// If there are quotes in one but not the other, then we know that some
|
// If there are quotes in one but not the other, then we know that some
|
||||||
// part of the heredoc word is quoted, so we shouldn't expand the content.
|
// part of the heredoc word is quoted, so we shouldn't expand the content.
|
||||||
shlex.RawQuotes = false
|
shlex.RawQuotes = false
|
||||||
words, err := shlex.ProcessWords(rest, []string{})
|
words, err := shlex.ProcessWords(rest, emptyEnvs{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -425,7 +428,7 @@ func heredocFromMatch(match []string) (*Heredoc, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
shlex.RawQuotes = true
|
shlex.RawQuotes = true
|
||||||
wordsRaw, err := shlex.ProcessWords(rest, []string{})
|
wordsRaw, err := shlex.ProcessWords(rest, emptyEnvs{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -466,7 +469,7 @@ func heredocsFromLine(line string) ([]Heredoc, error) {
|
||||||
shlex.RawQuotes = true
|
shlex.RawQuotes = true
|
||||||
shlex.RawEscapes = true
|
shlex.RawEscapes = true
|
||||||
shlex.SkipUnsetEnv = true
|
shlex.SkipUnsetEnv = true
|
||||||
words, _ := shlex.ProcessWords(line, []string{})
|
words, _ := shlex.ProcessWords(line, emptyEnvs{})
|
||||||
|
|
||||||
var docs []Heredoc
|
var docs []Heredoc
|
||||||
for _, word := range words {
|
for _, word := range words {
|
||||||
|
@ -487,7 +490,10 @@ func ChompHeredocContent(src string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func trimComments(src []byte) []byte {
|
func trimComments(src []byte) []byte {
|
||||||
return reComment.ReplaceAll(src, []byte{})
|
if !isComment(src) {
|
||||||
|
return src
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func trimLeadingWhitespace(src []byte) []byte {
|
func trimLeadingWhitespace(src []byte) []byte {
|
||||||
|
@ -501,7 +507,8 @@ func trimNewline(src []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func isComment(line []byte) bool {
|
func isComment(line []byte) bool {
|
||||||
return reComment.Match(trimLeadingWhitespace(trimNewline(line)))
|
line = trimLeadingWhitespace(line)
|
||||||
|
return len(line) > 0 && line[0] == '#'
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEmptyContinuationLine(line []byte) bool {
|
func isEmptyContinuationLine(line []byte) bool {
|
||||||
|
@ -510,9 +517,9 @@ func isEmptyContinuationLine(line []byte) bool {
|
||||||
|
|
||||||
var utf8bom = []byte{0xEF, 0xBB, 0xBF}
|
var utf8bom = []byte{0xEF, 0xBB, 0xBF}
|
||||||
|
|
||||||
func trimContinuationCharacter(line string, d *directives) (string, bool) {
|
func trimContinuationCharacter(line []byte, d *directives) ([]byte, bool) {
|
||||||
if d.lineContinuationRegex.MatchString(line) {
|
if d.lineContinuationRegex.Match(line) {
|
||||||
line = d.lineContinuationRegex.ReplaceAllString(line, "$1")
|
line = d.lineContinuationRegex.ReplaceAll(line, []byte("$1"))
|
||||||
return line, false
|
return line, false
|
||||||
}
|
}
|
||||||
return line, true
|
return line, true
|
||||||
|
@ -525,7 +532,7 @@ func processLine(d *directives, token []byte, stripLeftWhitespace bool) ([]byte,
|
||||||
if stripLeftWhitespace {
|
if stripLeftWhitespace {
|
||||||
token = trimLeadingWhitespace(token)
|
token = trimLeadingWhitespace(token)
|
||||||
}
|
}
|
||||||
return trimComments(token), d.possibleParserDirective(string(token))
|
return trimComments(token), d.possibleParserDirective(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variation of bufio.ScanLines that preserves the line endings
|
// Variation of bufio.ScanLines that preserves the line endings
|
||||||
|
@ -550,3 +557,13 @@ func handleScannerError(err error) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type emptyEnvs struct{}
|
||||||
|
|
||||||
|
func (emptyEnvs) Get(string) (string, bool) {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (emptyEnvs) Keys() []string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ func extractBuilderFlags(line string) (string, []string, error) {
|
||||||
|
|
||||||
words := []string{}
|
words := []string{}
|
||||||
phase := inSpaces
|
phase := inSpaces
|
||||||
word := ""
|
sbuilder := &strings.Builder{}
|
||||||
quote := '\000'
|
quote := '\000'
|
||||||
blankOK := false
|
blankOK := false
|
||||||
var ch rune
|
var ch rune
|
||||||
|
@ -62,13 +62,14 @@ func extractBuilderFlags(line string) (string, []string, error) {
|
||||||
phase = inWord // found something with "--", fall through
|
phase = inWord // found something with "--", fall through
|
||||||
}
|
}
|
||||||
if (phase == inWord || phase == inQuote) && (pos == len(line)) {
|
if (phase == inWord || phase == inQuote) && (pos == len(line)) {
|
||||||
if word != "--" && (blankOK || len(word) > 0) {
|
if word := sbuilder.String(); word != "--" && (blankOK || len(word) > 0) {
|
||||||
words = append(words, word)
|
words = append(words, word)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if phase == inWord {
|
if phase == inWord {
|
||||||
if unicode.IsSpace(ch) {
|
if unicode.IsSpace(ch) {
|
||||||
|
word := sbuilder.String()
|
||||||
phase = inSpaces
|
phase = inSpaces
|
||||||
if word == "--" {
|
if word == "--" {
|
||||||
return line[pos:], words, nil
|
return line[pos:], words, nil
|
||||||
|
@ -76,7 +77,7 @@ func extractBuilderFlags(line string) (string, []string, error) {
|
||||||
if blankOK || len(word) > 0 {
|
if blankOK || len(word) > 0 {
|
||||||
words = append(words, word)
|
words = append(words, word)
|
||||||
}
|
}
|
||||||
word = ""
|
sbuilder.Reset()
|
||||||
blankOK = false
|
blankOK = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -93,7 +94,9 @@ func extractBuilderFlags(line string) (string, []string, error) {
|
||||||
pos++
|
pos++
|
||||||
ch = rune(line[pos])
|
ch = rune(line[pos])
|
||||||
}
|
}
|
||||||
word += string(ch)
|
if _, err := sbuilder.WriteRune(ch); err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if phase == inQuote {
|
if phase == inQuote {
|
||||||
|
@ -109,7 +112,9 @@ func extractBuilderFlags(line string) (string, []string, error) {
|
||||||
pos++
|
pos++
|
||||||
ch = rune(line[pos])
|
ch = rune(line[pos])
|
||||||
}
|
}
|
||||||
word += string(ch)
|
if _, err := sbuilder.WriteRune(ch); err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,3 +9,10 @@ package shell
|
||||||
func EqualEnvKeys(from, to string) bool {
|
func EqualEnvKeys(from, to string) bool {
|
||||||
return from == to
|
return from == to
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NormalizeEnvKey returns the key in a normalized form that can be used
|
||||||
|
// for comparison. On Unix this is a no-op. On Windows this converts the
|
||||||
|
// key to uppercase.
|
||||||
|
func NormalizeEnvKey(key string) string {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
|
@ -8,3 +8,10 @@ import "strings"
|
||||||
func EqualEnvKeys(from, to string) bool {
|
func EqualEnvKeys(from, to string) bool {
|
||||||
return strings.EqualFold(from, to)
|
return strings.EqualFold(from, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NormalizeEnvKey returns the key in a normalized form that can be used
|
||||||
|
// for comparison. On Unix this is a no-op. On Windows this converts the
|
||||||
|
// key to uppercase.
|
||||||
|
func NormalizeEnvKey(key string) string {
|
||||||
|
return strings.ToUpper(key)
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package shell
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"text/scanner"
|
"text/scanner"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
@ -10,6 +12,11 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type EnvGetter interface {
|
||||||
|
Get(string) (string, bool)
|
||||||
|
Keys() []string
|
||||||
|
}
|
||||||
|
|
||||||
// Lex performs shell word splitting and variable expansion.
|
// Lex performs shell word splitting and variable expansion.
|
||||||
//
|
//
|
||||||
// Lex takes a string and an array of env variables and
|
// Lex takes a string and an array of env variables and
|
||||||
|
@ -17,12 +24,15 @@ import (
|
||||||
// tokens. Tries to mimic bash shell process.
|
// tokens. Tries to mimic bash shell process.
|
||||||
// It doesn't support all flavors of ${xx:...} formats but new ones can
|
// It doesn't support all flavors of ${xx:...} formats but new ones can
|
||||||
// be added by adding code to the "special ${} format processing" section
|
// be added by adding code to the "special ${} format processing" section
|
||||||
|
//
|
||||||
|
// It is not safe to call methods on a Lex instance concurrently.
|
||||||
type Lex struct {
|
type Lex struct {
|
||||||
escapeToken rune
|
escapeToken rune
|
||||||
RawQuotes bool
|
RawQuotes bool
|
||||||
RawEscapes bool
|
RawEscapes bool
|
||||||
SkipProcessQuotes bool
|
SkipProcessQuotes bool
|
||||||
SkipUnsetEnv bool
|
SkipUnsetEnv bool
|
||||||
|
shellWord shellWord
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLex creates a new Lex which uses escapeToken to escape quotes.
|
// NewLex creates a new Lex which uses escapeToken to escape quotes.
|
||||||
|
@ -31,10 +41,13 @@ func NewLex(escapeToken rune) *Lex {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessWord will use the 'env' list of environment variables,
|
// ProcessWord will use the 'env' list of environment variables,
|
||||||
// and replace any env var references in 'word'.
|
// and replace any env var references in 'word'. It will also
|
||||||
func (s *Lex) ProcessWord(word string, env []string) (string, error) {
|
// return variables in word which were not found in the 'env' list,
|
||||||
word, _, err := s.process(word, BuildEnvs(env))
|
// which is useful in later linting.
|
||||||
return word, err
|
// TODO: rename
|
||||||
|
func (s *Lex) ProcessWord(word string, env EnvGetter) (string, map[string]struct{}, error) {
|
||||||
|
result, err := s.process(word, env, true)
|
||||||
|
return result.Result, result.Unmatched, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessWords will use the 'env' list of environment variables,
|
// ProcessWords will use the 'env' list of environment variables,
|
||||||
|
@ -44,63 +57,62 @@ func (s *Lex) ProcessWord(word string, env []string) (string, error) {
|
||||||
// this splitting is done **after** the env var substitutions are done.
|
// this splitting is done **after** the env var substitutions are done.
|
||||||
// Note, each one is trimmed to remove leading and trailing spaces (unless
|
// Note, each one is trimmed to remove leading and trailing spaces (unless
|
||||||
// they are quoted", but ProcessWord retains spaces between words.
|
// they are quoted", but ProcessWord retains spaces between words.
|
||||||
func (s *Lex) ProcessWords(word string, env []string) ([]string, error) {
|
func (s *Lex) ProcessWords(word string, env EnvGetter) ([]string, error) {
|
||||||
_, words, err := s.process(word, BuildEnvs(env))
|
result, err := s.process(word, env, false)
|
||||||
return words, err
|
return result.Words, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessWordWithMap will use the 'env' list of environment variables,
|
type ProcessWordResult struct {
|
||||||
// and replace any env var references in 'word'.
|
Result string
|
||||||
func (s *Lex) ProcessWordWithMap(word string, env map[string]string) (string, error) {
|
Words []string
|
||||||
word, _, err := s.process(word, env)
|
Matched map[string]struct{}
|
||||||
return word, err
|
Unmatched map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessWordWithMatches will use the 'env' list of environment variables,
|
// ProcessWordWithMatches will use the 'env' list of environment variables,
|
||||||
// replace any env var references in 'word' and return the env that were used.
|
// replace any env var references in 'word' and return the env that were used.
|
||||||
func (s *Lex) ProcessWordWithMatches(word string, env map[string]string) (string, map[string]struct{}, error) {
|
func (s *Lex) ProcessWordWithMatches(word string, env EnvGetter) (ProcessWordResult, error) {
|
||||||
sw := s.init(word, env)
|
return s.process(word, env, true)
|
||||||
word, _, err := sw.process(word)
|
|
||||||
return word, sw.matches, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Lex) ProcessWordsWithMap(word string, env map[string]string) ([]string, error) {
|
func (s *Lex) initWord(word string, env EnvGetter, capture bool) *shellWord {
|
||||||
_, words, err := s.process(word, env)
|
sw := &s.shellWord
|
||||||
return words, err
|
sw.Lex = s
|
||||||
}
|
sw.envs = env
|
||||||
|
sw.capture = capture
|
||||||
func (s *Lex) init(word string, env map[string]string) *shellWord {
|
sw.rawEscapes = s.RawEscapes
|
||||||
sw := &shellWord{
|
if capture {
|
||||||
envs: env,
|
sw.matches = nil
|
||||||
escapeToken: s.escapeToken,
|
sw.nonmatches = nil
|
||||||
skipUnsetEnv: s.SkipUnsetEnv,
|
|
||||||
skipProcessQuotes: s.SkipProcessQuotes,
|
|
||||||
rawQuotes: s.RawQuotes,
|
|
||||||
rawEscapes: s.RawEscapes,
|
|
||||||
matches: make(map[string]struct{}),
|
|
||||||
}
|
}
|
||||||
sw.scanner.Init(strings.NewReader(word))
|
sw.scanner.Init(strings.NewReader(word))
|
||||||
return sw
|
return sw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Lex) process(word string, env map[string]string) (string, []string, error) {
|
func (s *Lex) process(word string, env EnvGetter, capture bool) (ProcessWordResult, error) {
|
||||||
sw := s.init(word, env)
|
sw := s.initWord(word, env, capture)
|
||||||
return sw.process(word)
|
word, words, err := sw.process(word)
|
||||||
|
return ProcessWordResult{
|
||||||
|
Result: word,
|
||||||
|
Words: words,
|
||||||
|
Matched: sw.matches,
|
||||||
|
Unmatched: sw.nonmatches,
|
||||||
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type shellWord struct {
|
type shellWord struct {
|
||||||
scanner scanner.Scanner
|
*Lex
|
||||||
envs map[string]string
|
wordsBuffer strings.Builder
|
||||||
escapeToken rune
|
scanner scanner.Scanner
|
||||||
rawQuotes bool
|
envs EnvGetter
|
||||||
rawEscapes bool
|
rawEscapes bool
|
||||||
skipUnsetEnv bool
|
capture bool // capture matches and nonmatches
|
||||||
skipProcessQuotes bool
|
matches map[string]struct{}
|
||||||
matches map[string]struct{}
|
nonmatches map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sw *shellWord) process(source string) (string, []string, error) {
|
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 {
|
if err != nil {
|
||||||
err = errors.Wrapf(err, "failed to process %q", source)
|
err = errors.Wrapf(err, "failed to process %q", source)
|
||||||
}
|
}
|
||||||
|
@ -108,16 +120,16 @@ func (sw *shellWord) process(source string) (string, []string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type wordsStruct struct {
|
type wordsStruct struct {
|
||||||
word string
|
buf *strings.Builder
|
||||||
words []string
|
words []string
|
||||||
inWord bool
|
inWord bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *wordsStruct) addChar(ch rune) {
|
func (w *wordsStruct) addChar(ch rune) {
|
||||||
if unicode.IsSpace(ch) && w.inWord {
|
if unicode.IsSpace(ch) && w.inWord {
|
||||||
if len(w.word) != 0 {
|
if w.buf.Len() != 0 {
|
||||||
w.words = append(w.words, w.word)
|
w.words = append(w.words, w.buf.String())
|
||||||
w.word = ""
|
w.buf.Reset()
|
||||||
w.inWord = false
|
w.inWord = false
|
||||||
}
|
}
|
||||||
} else if !unicode.IsSpace(ch) {
|
} else if !unicode.IsSpace(ch) {
|
||||||
|
@ -126,7 +138,7 @@ func (w *wordsStruct) addChar(ch rune) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *wordsStruct) addRawChar(ch rune) {
|
func (w *wordsStruct) addRawChar(ch rune) {
|
||||||
w.word += string(ch)
|
w.buf.WriteRune(ch)
|
||||||
w.inWord = true
|
w.inWord = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,16 +149,16 @@ func (w *wordsStruct) addString(str string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *wordsStruct) addRawString(str string) {
|
func (w *wordsStruct) addRawString(str string) {
|
||||||
w.word += str
|
w.buf.WriteString(str)
|
||||||
w.inWord = true
|
w.inWord = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *wordsStruct) getWords() []string {
|
func (w *wordsStruct) getWords() []string {
|
||||||
if len(w.word) > 0 {
|
if w.buf.Len() > 0 {
|
||||||
w.words = append(w.words, w.word)
|
w.words = append(w.words, w.buf.String())
|
||||||
|
|
||||||
// Just in case we're called again by mistake
|
// Just in case we're called again by mistake
|
||||||
w.word = ""
|
w.buf.Reset()
|
||||||
w.inWord = false
|
w.inWord = false
|
||||||
}
|
}
|
||||||
return w.words
|
return w.words
|
||||||
|
@ -154,18 +166,31 @@ func (w *wordsStruct) getWords() []string {
|
||||||
|
|
||||||
// Process the word, starting at 'pos', and stop when we get to the
|
// Process the word, starting at 'pos', and stop when we get to the
|
||||||
// end of the word or the 'stopChar' character
|
// 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
|
// result buffer can't be currently shared for shellWord as it is called internally
|
||||||
|
// by processDollar
|
||||||
|
var result strings.Builder
|
||||||
|
sw.wordsBuffer.Reset()
|
||||||
var words wordsStruct
|
var words wordsStruct
|
||||||
|
words.buf = &sw.wordsBuffer
|
||||||
|
|
||||||
|
// no need to initialize all the time
|
||||||
var charFuncMapping = map[rune]func() (string, error){
|
var charFuncMapping = map[rune]func() (string, error){
|
||||||
'$': sw.processDollar,
|
'$': sw.processDollar,
|
||||||
}
|
}
|
||||||
if !sw.skipProcessQuotes {
|
if !sw.SkipProcessQuotes {
|
||||||
charFuncMapping['\''] = sw.processSingleQuote
|
charFuncMapping['\''] = sw.processSingleQuote
|
||||||
charFuncMapping['"'] = sw.processDoubleQuote
|
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 {
|
for sw.scanner.Peek() != scanner.EOF {
|
||||||
ch := sw.scanner.Peek()
|
ch := sw.scanner.Peek()
|
||||||
|
|
||||||
|
@ -230,7 +255,7 @@ func (sw *shellWord) processSingleQuote() (string, error) {
|
||||||
var result bytes.Buffer
|
var result bytes.Buffer
|
||||||
|
|
||||||
ch := sw.scanner.Next()
|
ch := sw.scanner.Next()
|
||||||
if sw.rawQuotes {
|
if sw.RawQuotes {
|
||||||
result.WriteRune(ch)
|
result.WriteRune(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +265,7 @@ func (sw *shellWord) processSingleQuote() (string, error) {
|
||||||
case scanner.EOF:
|
case scanner.EOF:
|
||||||
return "", errors.New("unexpected end of statement while looking for matching single-quote")
|
return "", errors.New("unexpected end of statement while looking for matching single-quote")
|
||||||
case '\'':
|
case '\'':
|
||||||
if sw.rawQuotes {
|
if sw.RawQuotes {
|
||||||
result.WriteRune(ch)
|
result.WriteRune(ch)
|
||||||
}
|
}
|
||||||
return result.String(), nil
|
return result.String(), nil
|
||||||
|
@ -265,7 +290,7 @@ func (sw *shellWord) processDoubleQuote() (string, error) {
|
||||||
var result bytes.Buffer
|
var result bytes.Buffer
|
||||||
|
|
||||||
ch := sw.scanner.Next()
|
ch := sw.scanner.Next()
|
||||||
if sw.rawQuotes {
|
if sw.RawQuotes {
|
||||||
result.WriteRune(ch)
|
result.WriteRune(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +300,7 @@ func (sw *shellWord) processDoubleQuote() (string, error) {
|
||||||
return "", errors.New("unexpected end of statement while looking for matching double-quote")
|
return "", errors.New("unexpected end of statement while looking for matching double-quote")
|
||||||
case '"':
|
case '"':
|
||||||
ch := sw.scanner.Next()
|
ch := sw.scanner.Next()
|
||||||
if sw.rawQuotes {
|
if sw.RawQuotes {
|
||||||
result.WriteRune(ch)
|
result.WriteRune(ch)
|
||||||
}
|
}
|
||||||
return result.String(), nil
|
return result.String(), nil
|
||||||
|
@ -319,7 +344,7 @@ func (sw *shellWord) processDollar() (string, error) {
|
||||||
return "$", nil
|
return "$", nil
|
||||||
}
|
}
|
||||||
value, found := sw.getEnv(name)
|
value, found := sw.getEnv(name)
|
||||||
if !found && sw.skipUnsetEnv {
|
if !found && sw.SkipUnsetEnv {
|
||||||
return "$" + name, nil
|
return "$" + name, nil
|
||||||
}
|
}
|
||||||
return value, nil
|
return value, nil
|
||||||
|
@ -342,7 +367,7 @@ func (sw *shellWord) processDollar() (string, error) {
|
||||||
case '}':
|
case '}':
|
||||||
// Normal ${xx} case
|
// Normal ${xx} case
|
||||||
value, set := sw.getEnv(name)
|
value, set := sw.getEnv(name)
|
||||||
if !set && sw.skipUnsetEnv {
|
if !set && sw.SkipUnsetEnv {
|
||||||
return fmt.Sprintf("${%s}", name), nil
|
return fmt.Sprintf("${%s}", name), nil
|
||||||
}
|
}
|
||||||
return value, nil
|
return value, nil
|
||||||
|
@ -351,8 +376,9 @@ func (sw *shellWord) processDollar() (string, error) {
|
||||||
ch = sw.scanner.Next()
|
ch = sw.scanner.Next()
|
||||||
chs += string(ch)
|
chs += string(ch)
|
||||||
fallthrough
|
fallthrough
|
||||||
case '+', '-', '?':
|
case '+', '-', '?', '#', '%':
|
||||||
word, _, err := sw.processStopOn('}')
|
rawEscapes := ch == '#' || ch == '%'
|
||||||
|
word, _, err := sw.processStopOn('}', rawEscapes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if sw.scanner.Peek() == scanner.EOF {
|
if sw.scanner.Peek() == scanner.EOF {
|
||||||
return "", errors.New("syntax error: missing '}'")
|
return "", errors.New("syntax error: missing '}'")
|
||||||
|
@ -363,7 +389,7 @@ func (sw *shellWord) processDollar() (string, error) {
|
||||||
// Grab the current value of the variable in question so we
|
// Grab the current value of the variable in question so we
|
||||||
// can use it to determine what to do based on the modifier
|
// can use it to determine what to do based on the modifier
|
||||||
value, set := sw.getEnv(name)
|
value, set := sw.getEnv(name)
|
||||||
if sw.skipUnsetEnv && !set {
|
if sw.SkipUnsetEnv && !set {
|
||||||
return fmt.Sprintf("${%s%s%s}", name, chs, word), nil
|
return fmt.Sprintf("${%s%s%s}", name, chs, word), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,9 +420,61 @@ func (sw *shellWord) processDollar() (string, error) {
|
||||||
return "", errors.Errorf("%s: %s", name, message)
|
return "", errors.Errorf("%s: %s", name, message)
|
||||||
}
|
}
|
||||||
return value, nil
|
return value, nil
|
||||||
|
case '%', '#':
|
||||||
|
// %/# matches the shortest pattern expansion, %%/## the longest
|
||||||
|
greedy := false
|
||||||
|
|
||||||
|
if len(word) > 0 && word[0] == byte(ch) {
|
||||||
|
greedy = true
|
||||||
|
word = word[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == '%' {
|
||||||
|
return trimSuffix(word, value, greedy)
|
||||||
|
}
|
||||||
|
return trimPrefix(word, value, greedy)
|
||||||
default:
|
default:
|
||||||
return "", errors.Errorf("unsupported modifier (%s) in substitution", chs)
|
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:
|
default:
|
||||||
return "", errors.Errorf("unsupported modifier (%s) in substitution", chs)
|
return "", errors.Errorf("unsupported modifier (%s) in substitution", chs)
|
||||||
}
|
}
|
||||||
|
@ -444,31 +522,155 @@ func isSpecialParam(char rune) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sw *shellWord) getEnv(name string) (string, bool) {
|
func (sw *shellWord) getEnv(name string) (string, bool) {
|
||||||
for key, value := range sw.envs {
|
v, ok := sw.envs.Get(name)
|
||||||
if EqualEnvKeys(name, key) {
|
if ok {
|
||||||
|
if sw.capture {
|
||||||
|
if sw.matches == nil {
|
||||||
|
sw.matches = make(map[string]struct{})
|
||||||
|
}
|
||||||
sw.matches[name] = struct{}{}
|
sw.matches[name] = struct{}{}
|
||||||
return value, true
|
|
||||||
}
|
}
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
if sw.capture {
|
||||||
|
if sw.nonmatches == nil {
|
||||||
|
sw.nonmatches = make(map[string]struct{})
|
||||||
|
}
|
||||||
|
sw.nonmatches[name] = struct{}{}
|
||||||
}
|
}
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildEnvs(env []string) map[string]string {
|
func EnvsFromSlice(env []string) EnvGetter {
|
||||||
envs := map[string]string{}
|
envs := map[string]string{}
|
||||||
|
keys := make([]string, 0, len(env))
|
||||||
for _, e := range env {
|
for _, e := range env {
|
||||||
i := strings.Index(e, "=")
|
k, v, _ := strings.Cut(e, "=")
|
||||||
|
keys = append(keys, k)
|
||||||
|
envs[NormalizeEnvKey(k)] = v
|
||||||
|
}
|
||||||
|
return &envGetter{env: envs, keys: keys}
|
||||||
|
}
|
||||||
|
|
||||||
if i < 0 {
|
type envGetter struct {
|
||||||
envs[e] = ""
|
env map[string]string
|
||||||
} else {
|
keys []string
|
||||||
k := e[:i]
|
}
|
||||||
v := e[i+1:]
|
|
||||||
|
|
||||||
// overwrite value if key already exists
|
var _ EnvGetter = &envGetter{}
|
||||||
envs[k] = v
|
|
||||||
}
|
func (e *envGetter) Get(key string) (string, bool) {
|
||||||
|
key = NormalizeEnvKey(key)
|
||||||
|
v, ok := e.env[key]
|
||||||
|
return v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *envGetter) Keys() []string {
|
||||||
|
return e.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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('^')
|
||||||
}
|
}
|
||||||
|
|
||||||
return envs
|
// 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)
|
||||||
|
slices.Reverse(out)
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,22 +46,23 @@ func Helper() {
|
||||||
func Traces(err error) []*Stack {
|
func Traces(err error) []*Stack {
|
||||||
var st []*Stack
|
var st []*Stack
|
||||||
|
|
||||||
wrapped, ok := err.(interface {
|
switch e := err.(type) {
|
||||||
Unwrap() error
|
case interface{ Unwrap() error }:
|
||||||
})
|
st = Traces(e.Unwrap())
|
||||||
if ok {
|
case interface{ Unwrap() []error }:
|
||||||
st = Traces(wrapped.Unwrap())
|
for _, ue := range e.Unwrap() {
|
||||||
|
st = Traces(ue)
|
||||||
|
// Only take first stack
|
||||||
|
if len(st) > 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ste, ok := err.(interface {
|
switch ste := err.(type) {
|
||||||
StackTrace() errors.StackTrace
|
case interface{ StackTrace() errors.StackTrace }:
|
||||||
}); ok {
|
|
||||||
st = append(st, convertStack(ste.StackTrace()))
|
st = append(st, convertStack(ste.StackTrace()))
|
||||||
}
|
case interface{ StackTrace() *Stack }:
|
||||||
|
|
||||||
if ste, ok := err.(interface {
|
|
||||||
StackTrace() *Stack
|
|
||||||
}); ok {
|
|
||||||
st = append(st, ste.StackTrace())
|
st = append(st, ste.StackTrace())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.30.0
|
// protoc-gen-go v1.33.0
|
||||||
// protoc v3.11.4
|
// protoc v3.11.4
|
||||||
// source: stack.proto
|
// source: stack.proto
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@ syntax = "proto3";
|
||||||
package stack;
|
package stack;
|
||||||
|
|
||||||
message Stack {
|
message Stack {
|
||||||
repeated Frame frames = 1;
|
repeated Frame frames = 1;
|
||||||
repeated string cmdline = 2;
|
repeated string cmdline = 2;
|
||||||
int32 pid = 3;
|
int32 pid = 3;
|
||||||
string version = 4;
|
string version = 4;
|
||||||
string revision = 5;
|
string revision = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Frame {
|
message Frame {
|
||||||
string Name = 1;
|
string Name = 1;
|
||||||
string File = 2;
|
string File = 2;
|
||||||
int32 Line = 3;
|
int32 Line = 3;
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- "1.20"
|
- "1.21.13"
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo systemctl stop docker.service && sudo systemctl stop docker.socket
|
- sudo systemctl stop docker.service && sudo systemctl stop docker.socket
|
||||||
|
|
|
@ -18,9 +18,10 @@ import (
|
||||||
|
|
||||||
docker "github.com/fsouza/go-dockerclient"
|
docker "github.com/fsouza/go-dockerclient"
|
||||||
|
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/platforms"
|
"github.com/containerd/platforms"
|
||||||
"github.com/containers/storage/pkg/regexp"
|
"github.com/containers/storage/pkg/regexp"
|
||||||
|
"github.com/openshift/imagebuilder/internal"
|
||||||
"github.com/openshift/imagebuilder/signal"
|
"github.com/openshift/imagebuilder/signal"
|
||||||
"github.com/openshift/imagebuilder/strslice"
|
"github.com/openshift/imagebuilder/strslice"
|
||||||
|
|
||||||
|
@ -143,7 +144,7 @@ func processHereDocs(instruction, originalInstruction string, heredocs []buildki
|
||||||
shlex := buildkitshell.NewLex('\\')
|
shlex := buildkitshell.NewLex('\\')
|
||||||
shlex.RawQuotes = true
|
shlex.RawQuotes = true
|
||||||
shlex.RawEscapes = true
|
shlex.RawEscapes = true
|
||||||
content, err = shlex.ProcessWord(content, args)
|
content, _, err = shlex.ProcessWord(content, internal.EnvironmentSlice(args))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
buildkitparser "github.com/moby/buildkit/frontend/dockerfile/parser"
|
buildkitparser "github.com/moby/buildkit/frontend/dockerfile/parser"
|
||||||
buildkitshell "github.com/moby/buildkit/frontend/dockerfile/shell"
|
buildkitshell "github.com/moby/buildkit/frontend/dockerfile/shell"
|
||||||
"github.com/openshift/imagebuilder/dockerfile/command"
|
"github.com/openshift/imagebuilder/dockerfile/command"
|
||||||
|
"github.com/openshift/imagebuilder/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Node is a structure used to represent a parse tree.
|
// Node is a structure used to represent a parse tree.
|
||||||
|
@ -408,7 +409,7 @@ func heredocsFromLine(line string) ([]buildkitparser.Heredoc, error) {
|
||||||
shlex.RawQuotes = true
|
shlex.RawQuotes = true
|
||||||
shlex.RawEscapes = true
|
shlex.RawEscapes = true
|
||||||
shlex.SkipUnsetEnv = true
|
shlex.SkipUnsetEnv = true
|
||||||
words, _ := shlex.ProcessWords(line, []string{})
|
words, _ := shlex.ProcessWords(line, internal.EnvironmentSlice([]string{}))
|
||||||
|
|
||||||
var docs []buildkitparser.Heredoc
|
var docs []buildkitparser.Heredoc
|
||||||
for _, word := range words {
|
for _, word := range words {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
%global golang_version 1.19
|
%global golang_version 1.19
|
||||||
%{!?version: %global version 1.2.14}
|
%{!?version: %global version 1.2.15}
|
||||||
%{!?release: %global release 1}
|
%{!?release: %global release 1}
|
||||||
%global package_name imagebuilder
|
%global package_name imagebuilder
|
||||||
%global product_name Container Image Builder
|
%global product_name Container Image Builder
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type EnvironmentSlice []string
|
||||||
|
|
||||||
|
func (e EnvironmentSlice) Keys() []string {
|
||||||
|
keys := make([]string, 0, len(e))
|
||||||
|
for _, kv := range e {
|
||||||
|
k, _, _ := strings.Cut(kv, "=")
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EnvironmentSlice) Get(key string) (string, bool) {
|
||||||
|
for _, kv := range e {
|
||||||
|
if k, v, ok := strings.Cut(kv, "="); ok && k == key {
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
|
@ -107,9 +107,8 @@ github.com/chzyer/readline
|
||||||
# github.com/containerd/cgroups/v3 v3.0.3
|
# github.com/containerd/cgroups/v3 v3.0.3
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/containerd/cgroups/v3/cgroup1/stats
|
github.com/containerd/cgroups/v3/cgroup1/stats
|
||||||
# github.com/containerd/containerd v1.7.18
|
# github.com/containerd/containerd v1.7.20
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
github.com/containerd/containerd/errdefs
|
|
||||||
github.com/containerd/containerd/platforms
|
github.com/containerd/containerd/platforms
|
||||||
# github.com/containerd/errdefs v0.1.0
|
# github.com/containerd/errdefs v0.1.0
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
|
@ -117,6 +116,9 @@ github.com/containerd/errdefs
|
||||||
# github.com/containerd/log v0.1.0
|
# github.com/containerd/log v0.1.0
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
github.com/containerd/log
|
github.com/containerd/log
|
||||||
|
# github.com/containerd/platforms v0.2.1
|
||||||
|
## explicit; go 1.20
|
||||||
|
github.com/containerd/platforms
|
||||||
# github.com/containerd/stargz-snapshotter/estargz v0.15.1
|
# github.com/containerd/stargz-snapshotter/estargz v0.15.1
|
||||||
## explicit; go 1.19
|
## explicit; go 1.19
|
||||||
github.com/containerd/stargz-snapshotter/estargz
|
github.com/containerd/stargz-snapshotter/estargz
|
||||||
|
@ -525,7 +527,7 @@ github.com/felixge/httpsnoop
|
||||||
# github.com/fsnotify/fsnotify v1.7.0
|
# github.com/fsnotify/fsnotify v1.7.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
github.com/fsnotify/fsnotify
|
github.com/fsnotify/fsnotify
|
||||||
# github.com/fsouza/go-dockerclient v1.11.1
|
# github.com/fsouza/go-dockerclient v1.11.2
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
github.com/fsouza/go-dockerclient
|
github.com/fsouza/go-dockerclient
|
||||||
# github.com/gabriel-vasile/mimetype v1.4.3
|
# github.com/gabriel-vasile/mimetype v1.4.3
|
||||||
|
@ -792,8 +794,8 @@ github.com/mistifyio/go-zfs/v3
|
||||||
# github.com/mitchellh/mapstructure v1.5.0
|
# github.com/mitchellh/mapstructure v1.5.0
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
github.com/mitchellh/mapstructure
|
github.com/mitchellh/mapstructure
|
||||||
# github.com/moby/buildkit v0.12.5
|
# github.com/moby/buildkit v0.15.1
|
||||||
## explicit; go 1.20
|
## explicit; go 1.21.0
|
||||||
github.com/moby/buildkit/frontend/dockerfile/command
|
github.com/moby/buildkit/frontend/dockerfile/command
|
||||||
github.com/moby/buildkit/frontend/dockerfile/parser
|
github.com/moby/buildkit/frontend/dockerfile/parser
|
||||||
github.com/moby/buildkit/frontend/dockerfile/shell
|
github.com/moby/buildkit/frontend/dockerfile/shell
|
||||||
|
@ -909,11 +911,12 @@ github.com/opencontainers/runtime-tools/validate/capabilities
|
||||||
github.com/opencontainers/selinux/go-selinux
|
github.com/opencontainers/selinux/go-selinux
|
||||||
github.com/opencontainers/selinux/go-selinux/label
|
github.com/opencontainers/selinux/go-selinux/label
|
||||||
github.com/opencontainers/selinux/pkg/pwalkdir
|
github.com/opencontainers/selinux/pkg/pwalkdir
|
||||||
# github.com/openshift/imagebuilder v1.2.14
|
# github.com/openshift/imagebuilder v1.2.15
|
||||||
## explicit; go 1.19
|
## explicit; go 1.21.0
|
||||||
github.com/openshift/imagebuilder
|
github.com/openshift/imagebuilder
|
||||||
github.com/openshift/imagebuilder/dockerfile/command
|
github.com/openshift/imagebuilder/dockerfile/command
|
||||||
github.com/openshift/imagebuilder/dockerfile/parser
|
github.com/openshift/imagebuilder/dockerfile/parser
|
||||||
|
github.com/openshift/imagebuilder/internal
|
||||||
github.com/openshift/imagebuilder/signal
|
github.com/openshift/imagebuilder/signal
|
||||||
github.com/openshift/imagebuilder/strslice
|
github.com/openshift/imagebuilder/strslice
|
||||||
# github.com/opentracing/opentracing-go v1.2.0
|
# github.com/opentracing/opentracing-go v1.2.0
|
||||||
|
|
Loading…
Reference in New Issue