mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 01:06:27 +00:00
remote-tag enable copying across repositories and registries
Signed-off-by: Avi Deitcher <avi@deitcher.net>
This commit is contained in:
parent
0d89422386
commit
51696d2905
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/crane"
|
||||
namepkg "github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/util"
|
||||
@ -19,9 +20,13 @@ func pkgRemoteTagCmd() *cobra.Command {
|
||||
Long: `Tag a package in a remote registry with another tag, without downloading or pulling.
|
||||
Will simply tag using the identical descriptor.
|
||||
First argument is "from" tag, second is "to" tag.
|
||||
|
||||
If the "to" and "from" repositories are the same, then it is a simple tag operation.
|
||||
If they are not, then the "from" image is pulled and pushed to the "to" repository.
|
||||
`,
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
var finalErr error
|
||||
from := args[0]
|
||||
to := args[1]
|
||||
remoteOptions := []remote.Option{remote.WithAuthFromKeychain(authn.DefaultKeychain)}
|
||||
@ -48,15 +53,19 @@ func pkgRemoteTagCmd() *cobra.Command {
|
||||
}
|
||||
log.Infof("image %s already exists in the registry, but is different from %s, overwriting", toFullname, fromFullname)
|
||||
}
|
||||
toTag, err := namepkg.NewTag(toFullname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := remote.Tag(toTag, fromDesc, remoteOptions...); err != nil {
|
||||
return fmt.Errorf("error tagging image %s as %s: %v", fromFullname, toFullname, err)
|
||||
// see if they are from the same sources
|
||||
if fromRef.Context().String() == toRef.Context().String() {
|
||||
toTag, err := namepkg.NewTag(toFullname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
finalErr = remote.Tag(toTag, fromDesc, remoteOptions...)
|
||||
} else {
|
||||
// different, so need to copy
|
||||
finalErr = crane.Copy(fromFullname, toFullname)
|
||||
}
|
||||
|
||||
return nil
|
||||
return finalErr
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVar(&release, "release", "", "Release the given version")
|
||||
|
191
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/v2/LICENSE
generated
vendored
191
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/v2/LICENSE
generated
vendored
@ -1,191 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://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 2016 Antonio Murdaca <runcom@redhat.com>
|
||||
|
||||
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.
|
48
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/v2/pkg/util/name.go
generated
vendored
48
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/v2/pkg/util/name.go
generated
vendored
@ -1,48 +0,0 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultHostname is the default built-in registry (DockerHub)
|
||||
DefaultHostname = "docker.io"
|
||||
// LegacyDefaultHostname is the old hostname used for DockerHub
|
||||
LegacyDefaultHostname = "index.docker.io"
|
||||
// DefaultRepoPrefix is the prefix used for official images in DockerHub
|
||||
DefaultRepoPrefix = "library/"
|
||||
)
|
||||
|
||||
func ParseName(name string) (reference.Named, error) {
|
||||
distref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hostname, remoteName := splitHostname(distref.String())
|
||||
if hostname == "" {
|
||||
return nil, fmt.Errorf("Please use a fully qualified repository name")
|
||||
}
|
||||
return reference.ParseNormalizedNamed(fmt.Sprintf("%s/%s", hostname, remoteName))
|
||||
}
|
||||
|
||||
// splitHostname splits a repository name to hostname and remotename string.
|
||||
// If no valid hostname is found, the default hostname is used. Repository name
|
||||
// needs to be already validated before.
|
||||
func splitHostname(name string) (hostname, remoteName string) {
|
||||
i := strings.IndexRune(name, '/')
|
||||
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
|
||||
hostname, remoteName = DefaultHostname, name
|
||||
} else {
|
||||
hostname, remoteName = name[:i], name[i+1:]
|
||||
}
|
||||
if hostname == LegacyDefaultHostname {
|
||||
hostname = DefaultHostname
|
||||
}
|
||||
if hostname == DefaultHostname && !strings.ContainsRune(remoteName, '/') {
|
||||
remoteName = DefaultRepoPrefix + remoteName
|
||||
}
|
||||
return
|
||||
}
|
42
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/v2/pkg/util/os.go
generated
vendored
42
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/v2/pkg/util/os.go
generated
vendored
@ -1,42 +0,0 @@
|
||||
package util
|
||||
|
||||
import "fmt"
|
||||
|
||||
//go:generate go run osgen.go
|
||||
|
||||
var (
|
||||
armVariants = map[string]bool{
|
||||
"v5": true,
|
||||
"v6": true,
|
||||
"v7": true,
|
||||
}
|
||||
)
|
||||
|
||||
// IsValidOSArch checks against the generated list of os/arch combinations
|
||||
// from Go as well as checking for valid variants for ARM (the only architecture that uses variants)
|
||||
func IsValidOSArch(os string, arch string, variant string) bool {
|
||||
osarch := fmt.Sprintf("%s/%s", os, arch)
|
||||
if _, ok := validOS[os]; !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := validArch[arch]; !ok {
|
||||
return false
|
||||
}
|
||||
if variant == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
// only arm/arm64 can use variant
|
||||
switch osarch {
|
||||
case "linux/arm":
|
||||
_, ok := armVariants[variant]
|
||||
return ok
|
||||
case "linux/arm64":
|
||||
if variant == "v8" {
|
||||
return true
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
36
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/v2/pkg/util/oslist.go
generated
vendored
36
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/v2/pkg/util/oslist.go
generated
vendored
@ -1,36 +0,0 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2021-02-09 13:11:28.537236306 -0500 EST m=+0.034330659
|
||||
// using data from 'go tool dist list'
|
||||
package util
|
||||
|
||||
var validOS = map[string]bool{
|
||||
"darwin": true,
|
||||
"dragonfly": true,
|
||||
"illumos": true,
|
||||
"js": true,
|
||||
"netbsd": true,
|
||||
"plan9": true,
|
||||
"aix": true,
|
||||
"android": true,
|
||||
"windows": true,
|
||||
"openbsd": true,
|
||||
"solaris": true,
|
||||
"freebsd": true,
|
||||
"linux": true,
|
||||
}
|
||||
var validArch = map[string]bool{
|
||||
"wasm": true,
|
||||
"mips": true,
|
||||
"mips64le": true,
|
||||
"mipsle": true,
|
||||
"ppc64le": true,
|
||||
"amd64": true,
|
||||
"arm64": true,
|
||||
"arm": true,
|
||||
"mips64": true,
|
||||
"riscv64": true,
|
||||
"s390x": true,
|
||||
"ppc64": true,
|
||||
"386": true,
|
||||
}
|
33
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/v2/pkg/util/resolver.go
generated
vendored
33
src/cmd/linuxkit/vendor/github.com/estesp/manifest-tool/v2/pkg/util/resolver.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
)
|
||||
|
||||
func NewResolver(username, password string, insecure, plainHTTP bool, configs ...string) remotes.Resolver {
|
||||
|
||||
opts := docker.ResolverOptions{
|
||||
PlainHTTP: plainHTTP,
|
||||
}
|
||||
client := http.DefaultClient
|
||||
if insecure {
|
||||
client.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
opts.Client = client
|
||||
|
||||
if username != "" || password != "" {
|
||||
opts.Credentials = func(hostName string) (string, string, error) {
|
||||
return username, password, nil
|
||||
}
|
||||
return docker.NewResolver(opts)
|
||||
}
|
||||
return docker.NewResolver(opts)
|
||||
}
|
57
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/internal/legacy/copy.go
generated
vendored
Normal file
57
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/internal/legacy/copy.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2019 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 legacy provides methods for interacting with legacy image formats.
|
||||
package legacy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
)
|
||||
|
||||
// CopySchema1 allows `[g]crane cp` to work with old images without adding
|
||||
// full support for schema 1 images to this package.
|
||||
func CopySchema1(desc *remote.Descriptor, srcRef, dstRef name.Reference, opts ...remote.Option) error {
|
||||
m := schema1{}
|
||||
if err := json.NewDecoder(bytes.NewReader(desc.Manifest)).Decode(&m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, layer := range m.FSLayers {
|
||||
src := srcRef.Context().Digest(layer.BlobSum)
|
||||
dst := dstRef.Context().Digest(layer.BlobSum)
|
||||
|
||||
blob, err := remote.Layer(src, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := remote.WriteLayer(dst.Context(), blob, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return remote.Put(dstRef, desc, opts...)
|
||||
}
|
||||
|
||||
type fslayer struct {
|
||||
BlobSum string `json:"blobSum"`
|
||||
}
|
||||
|
||||
type schema1 struct {
|
||||
FSLayers []fslayer `json:"fsLayers"`
|
||||
}
|
72
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/append.go
generated
vendored
Normal file
72
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/append.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
"github.com/google/go-containerregistry/pkg/v1/stream"
|
||||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||
)
|
||||
|
||||
// Append reads a layer from path and appends it the the v1.Image base.
|
||||
func Append(base v1.Image, paths ...string) (v1.Image, error) {
|
||||
layers := make([]v1.Layer, 0, len(paths))
|
||||
for _, path := range paths {
|
||||
layer, err := getLayer(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading layer %q: %w", path, err)
|
||||
}
|
||||
|
||||
layers = append(layers, layer)
|
||||
}
|
||||
|
||||
return mutate.AppendLayers(base, layers...)
|
||||
}
|
||||
|
||||
func getLayer(path string) (v1.Layer, error) {
|
||||
f, err := streamFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if f != nil {
|
||||
return stream.NewLayer(f), nil
|
||||
}
|
||||
|
||||
return tarball.LayerFromFile(path)
|
||||
}
|
||||
|
||||
// If we're dealing with a named pipe, trying to open it multiple times will
|
||||
// fail, so we need to do a streaming upload.
|
||||
//
|
||||
// returns nil, nil for non-streaming files
|
||||
func streamFile(path string) (*os.File, error) {
|
||||
if path == "-" {
|
||||
return os.Stdin, nil
|
||||
}
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !fi.Mode().IsRegular() {
|
||||
return os.Open(path)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
35
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/catalog.go
generated
vendored
Normal file
35
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/catalog.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2019 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
)
|
||||
|
||||
// Catalog returns the repositories in a registry's catalog.
|
||||
func Catalog(src string, opt ...Option) (res []string, err error) {
|
||||
o := makeOptions(opt...)
|
||||
reg, err := name.NewRegistry(src, o.Name...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// This context gets overridden by remote.WithContext, which is set by
|
||||
// crane.WithContext.
|
||||
return remote.Catalog(context.Background(), reg, o.Remote...)
|
||||
}
|
24
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/config.go
generated
vendored
Normal file
24
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/config.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
// Config returns the config file for the remote image ref.
|
||||
func Config(ref string, opt ...Option) ([]byte, error) {
|
||||
i, _, err := getImage(ref, opt...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.RawConfigFile()
|
||||
}
|
88
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/copy.go
generated
vendored
Normal file
88
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/copy.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-containerregistry/internal/legacy"
|
||||
"github.com/google/go-containerregistry/pkg/logs"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||
)
|
||||
|
||||
// Copy copies a remote image or index from src to dst.
|
||||
func Copy(src, dst string, opt ...Option) error {
|
||||
o := makeOptions(opt...)
|
||||
srcRef, err := name.ParseReference(src, o.Name...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing reference %q: %w", src, err)
|
||||
}
|
||||
|
||||
dstRef, err := name.ParseReference(dst, o.Name...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing reference for %q: %w", dst, err)
|
||||
}
|
||||
|
||||
logs.Progress.Printf("Copying from %v to %v", srcRef, dstRef)
|
||||
desc, err := remote.Get(srcRef, o.Remote...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fetching %q: %w", src, err)
|
||||
}
|
||||
|
||||
switch desc.MediaType {
|
||||
case types.OCIImageIndex, types.DockerManifestList:
|
||||
// Handle indexes separately.
|
||||
if o.Platform != nil {
|
||||
// If platform is explicitly set, don't copy the whole index, just the appropriate image.
|
||||
if err := copyImage(desc, dstRef, o); err != nil {
|
||||
return fmt.Errorf("failed to copy image: %w", err)
|
||||
}
|
||||
} else {
|
||||
if err := copyIndex(desc, dstRef, o); err != nil {
|
||||
return fmt.Errorf("failed to copy index: %w", err)
|
||||
}
|
||||
}
|
||||
case types.DockerManifestSchema1, types.DockerManifestSchema1Signed:
|
||||
// Handle schema 1 images separately.
|
||||
if err := legacy.CopySchema1(desc, srcRef, dstRef, o.Remote...); err != nil {
|
||||
return fmt.Errorf("failed to copy schema 1 image: %w", err)
|
||||
}
|
||||
default:
|
||||
// Assume anything else is an image, since some registries don't set mediaTypes properly.
|
||||
if err := copyImage(desc, dstRef, o); err != nil {
|
||||
return fmt.Errorf("failed to copy image: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyImage(desc *remote.Descriptor, dstRef name.Reference, o Options) error {
|
||||
img, err := desc.Image()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return remote.Write(dstRef, img, o.Remote...)
|
||||
}
|
||||
|
||||
func copyIndex(desc *remote.Descriptor, dstRef name.Reference, o Options) error {
|
||||
idx, err := desc.ImageIndex()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return remote.WriteIndex(dstRef, idx, o.Remote...)
|
||||
}
|
33
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/delete.go
generated
vendored
Normal file
33
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/delete.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
)
|
||||
|
||||
// Delete deletes the remote reference at src.
|
||||
func Delete(src string, opt ...Option) error {
|
||||
o := makeOptions(opt...)
|
||||
ref, err := name.ParseReference(src, o.Name...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing reference %q: %w", src, err)
|
||||
}
|
||||
|
||||
return remote.Delete(ref, o.Remote...)
|
||||
}
|
52
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/digest.go
generated
vendored
Normal file
52
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/digest.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import "github.com/google/go-containerregistry/pkg/logs"
|
||||
|
||||
// Digest returns the sha256 hash of the remote image at ref.
|
||||
func Digest(ref string, opt ...Option) (string, error) {
|
||||
o := makeOptions(opt...)
|
||||
if o.Platform != nil {
|
||||
desc, err := getManifest(ref, opt...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !desc.MediaType.IsIndex() {
|
||||
return desc.Digest.String(), nil
|
||||
}
|
||||
|
||||
// TODO: does not work for indexes which contain schema v1 manifests
|
||||
img, err := desc.Image()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
digest, err := img.Digest()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return digest.String(), nil
|
||||
}
|
||||
desc, err := Head(ref, opt...)
|
||||
if err != nil {
|
||||
logs.Warn.Printf("HEAD request failed, falling back on GET: %v", err)
|
||||
rdesc, err := getManifest(ref, opt...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return rdesc.Digest.String(), nil
|
||||
}
|
||||
return desc.Digest.String(), nil
|
||||
}
|
16
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/doc.go
generated
vendored
Normal file
16
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/doc.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2019 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane holds libraries used to implement the crane CLI.
|
||||
package crane
|
29
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/export.go
generated
vendored
Normal file
29
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/export.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
)
|
||||
|
||||
// Export writes the filesystem contents (as a tarball) of img to w.
|
||||
func Export(img v1.Image, w io.Writer) error {
|
||||
fs := mutate.Extract(img)
|
||||
_, err := io.Copy(w, fs)
|
||||
return err
|
||||
}
|
67
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/filemap.go
generated
vendored
Normal file
67
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/filemap.go
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"sort"
|
||||
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||
)
|
||||
|
||||
// Layer creates a layer from a single file map. These layers are reproducible and consistent.
|
||||
// A filemap is a path -> file content map representing a file system.
|
||||
func Layer(filemap map[string][]byte) (v1.Layer, error) {
|
||||
b := &bytes.Buffer{}
|
||||
w := tar.NewWriter(b)
|
||||
|
||||
fn := []string{}
|
||||
for f := range filemap {
|
||||
fn = append(fn, f)
|
||||
}
|
||||
sort.Strings(fn)
|
||||
|
||||
for _, f := range fn {
|
||||
c := filemap[f]
|
||||
if err := w.WriteHeader(&tar.Header{
|
||||
Name: f,
|
||||
Size: int64(len(c)),
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := w.Write(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tarball.LayerFromReader(b)
|
||||
}
|
||||
|
||||
// Image creates a image with the given filemaps as its contents. These images are reproducible and consistent.
|
||||
// A filemap is a path -> file content map representing a file system.
|
||||
func Image(filemap map[string][]byte) (v1.Image, error) {
|
||||
y, err := Layer(filemap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mutate.AppendLayers(empty.Image, y)
|
||||
}
|
56
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/get.go
generated
vendored
Normal file
56
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/get.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
)
|
||||
|
||||
func getImage(r string, opt ...Option) (v1.Image, name.Reference, error) {
|
||||
o := makeOptions(opt...)
|
||||
ref, err := name.ParseReference(r, o.Name...)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("parsing reference %q: %w", r, err)
|
||||
}
|
||||
img, err := remote.Image(ref, o.Remote...)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("reading image %q: %w", ref, err)
|
||||
}
|
||||
return img, ref, nil
|
||||
}
|
||||
|
||||
func getManifest(r string, opt ...Option) (*remote.Descriptor, error) {
|
||||
o := makeOptions(opt...)
|
||||
ref, err := name.ParseReference(r, o.Name...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing reference %q: %w", r, err)
|
||||
}
|
||||
return remote.Get(ref, o.Remote...)
|
||||
}
|
||||
|
||||
// Head performs a HEAD request for a manifest and returns a content descriptor
|
||||
// based on the registry's response.
|
||||
func Head(r string, opt ...Option) (*v1.Descriptor, error) {
|
||||
o := makeOptions(opt...)
|
||||
ref, err := name.ParseReference(r, o.Name...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return remote.Head(ref, o.Remote...)
|
||||
}
|
33
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/list.go
generated
vendored
Normal file
33
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/list.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
)
|
||||
|
||||
// ListTags returns the tags in repository src.
|
||||
func ListTags(src string, opt ...Option) ([]string, error) {
|
||||
o := makeOptions(opt...)
|
||||
repo, err := name.NewRepository(src, o.Name...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing repo %q: %w", src, err)
|
||||
}
|
||||
|
||||
return remote.List(repo, o.Remote...)
|
||||
}
|
32
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/manifest.go
generated
vendored
Normal file
32
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/manifest.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
// Manifest returns the manifest for the remote image or index ref.
|
||||
func Manifest(ref string, opt ...Option) ([]byte, error) {
|
||||
desc, err := getManifest(ref, opt...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o := makeOptions(opt...)
|
||||
if o.Platform != nil {
|
||||
img, err := desc.Image()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return img.RawManifest()
|
||||
}
|
||||
return desc.Manifest, nil
|
||||
}
|
237
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/optimize.go
generated
vendored
Normal file
237
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/optimize.go
generated
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
// Copyright 2020 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/containerd/stargz-snapshotter/estargz"
|
||||
"github.com/google/go-containerregistry/pkg/logs"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||
)
|
||||
|
||||
// Optimize optimizes a remote image or index from src to dst.
|
||||
// THIS API IS EXPERIMENTAL AND SUBJECT TO CHANGE WITHOUT WARNING.
|
||||
func Optimize(src, dst string, prioritize []string, opt ...Option) error {
|
||||
pset := newStringSet(prioritize)
|
||||
o := makeOptions(opt...)
|
||||
srcRef, err := name.ParseReference(src, o.Name...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing reference %q: %w", src, err)
|
||||
}
|
||||
|
||||
dstRef, err := name.ParseReference(dst, o.Name...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing reference for %q: %w", dst, err)
|
||||
}
|
||||
|
||||
logs.Progress.Printf("Optimizing from %v to %v", srcRef, dstRef)
|
||||
desc, err := remote.Get(srcRef, o.Remote...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fetching %q: %w", src, err)
|
||||
}
|
||||
|
||||
switch desc.MediaType {
|
||||
case types.OCIImageIndex, types.DockerManifestList:
|
||||
// Handle indexes separately.
|
||||
if o.Platform != nil {
|
||||
// If platform is explicitly set, don't optimize the whole index, just the appropriate image.
|
||||
if err := optimizeAndPushImage(desc, dstRef, pset, o); err != nil {
|
||||
return fmt.Errorf("failed to optimize image: %w", err)
|
||||
}
|
||||
} else {
|
||||
if err := optimizeAndPushIndex(desc, dstRef, pset, o); err != nil {
|
||||
return fmt.Errorf("failed to optimize index: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
case types.DockerManifestSchema1, types.DockerManifestSchema1Signed:
|
||||
return errors.New("docker schema 1 images are not supported")
|
||||
|
||||
default:
|
||||
// Assume anything else is an image, since some registries don't set mediaTypes properly.
|
||||
if err := optimizeAndPushImage(desc, dstRef, pset, o); err != nil {
|
||||
return fmt.Errorf("failed to optimize image: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func optimizeAndPushImage(desc *remote.Descriptor, dstRef name.Reference, prioritize stringSet, o Options) error {
|
||||
img, err := desc.Image()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
missing, oimg, err := optimizeImage(img, prioritize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(missing) > 0 {
|
||||
return fmt.Errorf("the following prioritized files were missing from image: %v", missing.List())
|
||||
}
|
||||
|
||||
return remote.Write(dstRef, oimg, o.Remote...)
|
||||
}
|
||||
|
||||
func optimizeImage(img v1.Image, prioritize stringSet) (stringSet, v1.Image, error) {
|
||||
cfg, err := img.ConfigFile()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ocfg := cfg.DeepCopy()
|
||||
ocfg.History = nil
|
||||
ocfg.RootFS.DiffIDs = nil
|
||||
|
||||
oimg, err := mutate.ConfigFile(empty.Image, ocfg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
layers, err := img.Layers()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
missingFromImage := newStringSet(prioritize.List())
|
||||
olayers := make([]mutate.Addendum, 0, len(layers))
|
||||
for _, layer := range layers {
|
||||
missingFromLayer := []string{}
|
||||
olayer, err := tarball.LayerFromOpener(layer.Uncompressed,
|
||||
tarball.WithEstargz,
|
||||
tarball.WithEstargzOptions(
|
||||
estargz.WithPrioritizedFiles(prioritize.List()),
|
||||
estargz.WithAllowPrioritizeNotFound(&missingFromLayer),
|
||||
))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
missingFromImage = missingFromImage.Intersection(newStringSet(missingFromLayer))
|
||||
|
||||
olayers = append(olayers, mutate.Addendum{
|
||||
Layer: olayer,
|
||||
MediaType: types.DockerLayer,
|
||||
})
|
||||
}
|
||||
|
||||
oimg, err = mutate.Append(oimg, olayers...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return missingFromImage, oimg, nil
|
||||
}
|
||||
|
||||
func optimizeAndPushIndex(desc *remote.Descriptor, dstRef name.Reference, prioritize stringSet, o Options) error {
|
||||
idx, err := desc.ImageIndex()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
missing, oidx, err := optimizeIndex(idx, prioritize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(missing) > 0 {
|
||||
return fmt.Errorf("the following prioritized files were missing from all images: %v", missing.List())
|
||||
}
|
||||
|
||||
return remote.WriteIndex(dstRef, oidx, o.Remote...)
|
||||
}
|
||||
|
||||
func optimizeIndex(idx v1.ImageIndex, prioritize stringSet) (stringSet, v1.ImageIndex, error) {
|
||||
im, err := idx.IndexManifest()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
missingFromIndex := newStringSet(prioritize.List())
|
||||
|
||||
// Build an image for each child from the base and append it to a new index to produce the result.
|
||||
adds := make([]mutate.IndexAddendum, 0, len(im.Manifests))
|
||||
for _, desc := range im.Manifests {
|
||||
img, err := idx.Image(desc.Digest)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
missingFromImage, oimg, err := optimizeImage(img, prioritize)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
missingFromIndex = missingFromIndex.Intersection(missingFromImage)
|
||||
adds = append(adds, mutate.IndexAddendum{
|
||||
Add: oimg,
|
||||
Descriptor: v1.Descriptor{
|
||||
URLs: desc.URLs,
|
||||
MediaType: desc.MediaType,
|
||||
Annotations: desc.Annotations,
|
||||
Platform: desc.Platform,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
idxType, err := idx.MediaType()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return missingFromIndex, mutate.IndexMediaType(mutate.AppendManifests(empty.Index, adds...), idxType), nil
|
||||
}
|
||||
|
||||
type stringSet map[string]struct{}
|
||||
|
||||
func newStringSet(in []string) stringSet {
|
||||
ss := stringSet{}
|
||||
for _, s := range in {
|
||||
ss[s] = struct{}{}
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
func (s stringSet) List() []string {
|
||||
result := make([]string, 0, len(s))
|
||||
for k := range s {
|
||||
result = append(result, k)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (s stringSet) Intersection(rhs stringSet) stringSet {
|
||||
// To appease ST1016
|
||||
lhs := s
|
||||
|
||||
// Make sure len(lhs) >= len(rhs)
|
||||
if len(lhs) < len(rhs) {
|
||||
return rhs.Intersection(lhs)
|
||||
}
|
||||
|
||||
result := stringSet{}
|
||||
for k := range lhs {
|
||||
if _, ok := rhs[k]; ok {
|
||||
result[k] = struct{}{}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
116
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/options.go
generated
vendored
Normal file
116
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/options.go
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2019 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
)
|
||||
|
||||
// Options hold the options that crane uses when calling other packages.
|
||||
type Options struct {
|
||||
Name []name.Option
|
||||
Remote []remote.Option
|
||||
Platform *v1.Platform
|
||||
}
|
||||
|
||||
// GetOptions exposes the underlying []remote.Option, []name.Option, and
|
||||
// platform, based on the passed Option. Generally, you shouldn't need to use
|
||||
// this unless you've painted yourself into a dependency corner as we have
|
||||
// with the crane and gcrane cli packages.
|
||||
func GetOptions(opts ...Option) Options {
|
||||
return makeOptions(opts...)
|
||||
}
|
||||
|
||||
func makeOptions(opts ...Option) Options {
|
||||
opt := Options{
|
||||
Remote: []remote.Option{
|
||||
remote.WithAuthFromKeychain(authn.DefaultKeychain),
|
||||
},
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
return opt
|
||||
}
|
||||
|
||||
// Option is a functional option for crane.
|
||||
type Option func(*Options)
|
||||
|
||||
// WithTransport is a functional option for overriding the default transport
|
||||
// for remote operations.
|
||||
func WithTransport(t http.RoundTripper) Option {
|
||||
return func(o *Options) {
|
||||
o.Remote = append(o.Remote, remote.WithTransport(t))
|
||||
}
|
||||
}
|
||||
|
||||
// Insecure is an Option that allows image references to be fetched without TLS.
|
||||
func Insecure(o *Options) {
|
||||
o.Name = append(o.Name, name.Insecure)
|
||||
}
|
||||
|
||||
// WithPlatform is an Option to specify the platform.
|
||||
func WithPlatform(platform *v1.Platform) Option {
|
||||
return func(o *Options) {
|
||||
if platform != nil {
|
||||
o.Remote = append(o.Remote, remote.WithPlatform(*platform))
|
||||
}
|
||||
o.Platform = platform
|
||||
}
|
||||
}
|
||||
|
||||
// WithAuthFromKeychain is a functional option for overriding the default
|
||||
// authenticator for remote operations, using an authn.Keychain to find
|
||||
// credentials.
|
||||
//
|
||||
// By default, crane will use authn.DefaultKeychain.
|
||||
func WithAuthFromKeychain(keys authn.Keychain) Option {
|
||||
return func(o *Options) {
|
||||
// Replace the default keychain at position 0.
|
||||
o.Remote[0] = remote.WithAuthFromKeychain(keys)
|
||||
}
|
||||
}
|
||||
|
||||
// WithAuth is a functional option for overriding the default authenticator
|
||||
// for remote operations.
|
||||
//
|
||||
// By default, crane will use authn.DefaultKeychain.
|
||||
func WithAuth(auth authn.Authenticator) Option {
|
||||
return func(o *Options) {
|
||||
// Replace the default keychain at position 0.
|
||||
o.Remote[0] = remote.WithAuth(auth)
|
||||
}
|
||||
}
|
||||
|
||||
// WithUserAgent adds the given string to the User-Agent header for any HTTP
|
||||
// requests.
|
||||
func WithUserAgent(ua string) Option {
|
||||
return func(o *Options) {
|
||||
o.Remote = append(o.Remote, remote.WithUserAgent(ua))
|
||||
}
|
||||
}
|
||||
|
||||
// WithContext is a functional option for setting the context.
|
||||
func WithContext(ctx context.Context) Option {
|
||||
return func(o *Options) {
|
||||
o.Remote = append(o.Remote, remote.WithContext(ctx))
|
||||
}
|
||||
}
|
142
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/pull.go
generated
vendored
Normal file
142
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/pull.go
generated
vendored
Normal file
@ -0,0 +1,142 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
legacy "github.com/google/go-containerregistry/pkg/legacy/tarball"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||
"github.com/google/go-containerregistry/pkg/v1/layout"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||
)
|
||||
|
||||
// Tag applied to images that were pulled by digest. This denotes that the
|
||||
// image was (probably) never tagged with this, but lets us avoid applying the
|
||||
// ":latest" tag which might be misleading.
|
||||
const iWasADigestTag = "i-was-a-digest"
|
||||
|
||||
// Pull returns a v1.Image of the remote image src.
|
||||
func Pull(src string, opt ...Option) (v1.Image, error) {
|
||||
o := makeOptions(opt...)
|
||||
ref, err := name.ParseReference(src, o.Name...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing reference %q: %w", src, err)
|
||||
}
|
||||
|
||||
return remote.Image(ref, o.Remote...)
|
||||
}
|
||||
|
||||
// Save writes the v1.Image img as a tarball at path with tag src.
|
||||
func Save(img v1.Image, src, path string) error {
|
||||
imgMap := map[string]v1.Image{src: img}
|
||||
return MultiSave(imgMap, path)
|
||||
}
|
||||
|
||||
// MultiSave writes collection of v1.Image img with tag as a tarball.
|
||||
func MultiSave(imgMap map[string]v1.Image, path string, opt ...Option) error {
|
||||
o := makeOptions(opt...)
|
||||
tagToImage := map[name.Tag]v1.Image{}
|
||||
|
||||
for src, img := range imgMap {
|
||||
ref, err := name.ParseReference(src, o.Name...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing ref %q: %w", src, err)
|
||||
}
|
||||
|
||||
// WriteToFile wants a tag to write to the tarball, but we might have
|
||||
// been given a digest.
|
||||
// If the original ref was a tag, use that. Otherwise, if it was a
|
||||
// digest, tag the image with :i-was-a-digest instead.
|
||||
tag, ok := ref.(name.Tag)
|
||||
if !ok {
|
||||
d, ok := ref.(name.Digest)
|
||||
if !ok {
|
||||
return fmt.Errorf("ref wasn't a tag or digest")
|
||||
}
|
||||
tag = d.Repository.Tag(iWasADigestTag)
|
||||
}
|
||||
tagToImage[tag] = img
|
||||
}
|
||||
// no progress channel (for now)
|
||||
return tarball.MultiWriteToFile(path, tagToImage)
|
||||
}
|
||||
|
||||
// PullLayer returns the given layer from a registry.
|
||||
func PullLayer(ref string, opt ...Option) (v1.Layer, error) {
|
||||
o := makeOptions(opt...)
|
||||
digest, err := name.NewDigest(ref, o.Name...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return remote.Layer(digest, o.Remote...)
|
||||
}
|
||||
|
||||
// SaveLegacy writes the v1.Image img as a legacy tarball at path with tag src.
|
||||
func SaveLegacy(img v1.Image, src, path string) error {
|
||||
imgMap := map[string]v1.Image{src: img}
|
||||
return MultiSave(imgMap, path)
|
||||
}
|
||||
|
||||
// MultiSaveLegacy writes collection of v1.Image img with tag as a legacy tarball.
|
||||
func MultiSaveLegacy(imgMap map[string]v1.Image, path string) error {
|
||||
refToImage := map[name.Reference]v1.Image{}
|
||||
|
||||
for src, img := range imgMap {
|
||||
ref, err := name.ParseReference(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing ref %q: %w", src, err)
|
||||
}
|
||||
refToImage[ref] = img
|
||||
}
|
||||
|
||||
w, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
return legacy.MultiWrite(refToImage, w)
|
||||
}
|
||||
|
||||
// SaveOCI writes the v1.Image img as an OCI Image Layout at path. If a layout
|
||||
// already exists at that path, it will add the image to the index.
|
||||
func SaveOCI(img v1.Image, path string) error {
|
||||
imgMap := map[string]v1.Image{"": img}
|
||||
return MultiSaveOCI(imgMap, path)
|
||||
}
|
||||
|
||||
// MultiSaveOCI writes collection of v1.Image img as an OCI Image Layout at path. If a layout
|
||||
// already exists at that path, it will add the image to the index.
|
||||
func MultiSaveOCI(imgMap map[string]v1.Image, path string) error {
|
||||
p, err := layout.FromPath(path)
|
||||
if err != nil {
|
||||
p, err = layout.Write(path, empty.Index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, img := range imgMap {
|
||||
if err = p.AppendImage(img); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
65
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/push.go
generated
vendored
Normal file
65
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/push.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2018 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||
)
|
||||
|
||||
// Load reads the tarball at path as a v1.Image.
|
||||
func Load(path string, opt ...Option) (v1.Image, error) {
|
||||
return LoadTag(path, "")
|
||||
}
|
||||
|
||||
// LoadTag reads a tag from the tarball at path as a v1.Image.
|
||||
// If tag is "", will attempt to read the tarball as a single image.
|
||||
func LoadTag(path, tag string, opt ...Option) (v1.Image, error) {
|
||||
if tag == "" {
|
||||
return tarball.ImageFromPath(path, nil)
|
||||
}
|
||||
|
||||
o := makeOptions(opt...)
|
||||
t, err := name.NewTag(tag, o.Name...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing tag %q: %w", tag, err)
|
||||
}
|
||||
return tarball.ImageFromPath(path, &t)
|
||||
}
|
||||
|
||||
// Push pushes the v1.Image img to a registry as dst.
|
||||
func Push(img v1.Image, dst string, opt ...Option) error {
|
||||
o := makeOptions(opt...)
|
||||
tag, err := name.ParseReference(dst, o.Name...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing reference %q: %w", dst, err)
|
||||
}
|
||||
return remote.Write(tag, img, o.Remote...)
|
||||
}
|
||||
|
||||
// Upload pushes the v1.Layer to a given repo.
|
||||
func Upload(layer v1.Layer, repo string, opt ...Option) error {
|
||||
o := makeOptions(opt...)
|
||||
ref, err := name.NewRepository(repo, o.Name...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing repo %q: %w", repo, err)
|
||||
}
|
||||
|
||||
return remote.WriteLayer(ref, layer, o.Remote...)
|
||||
}
|
39
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/tag.go
generated
vendored
Normal file
39
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/crane/tag.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2019 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 crane
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
)
|
||||
|
||||
// Tag adds tag to the remote img.
|
||||
func Tag(img, tag string, opt ...Option) error {
|
||||
o := makeOptions(opt...)
|
||||
ref, err := name.ParseReference(img, o.Name...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing reference %q: %w", img, err)
|
||||
}
|
||||
desc, err := remote.Get(ref, o.Remote...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fetching %q: %w", img, err)
|
||||
}
|
||||
|
||||
dst := ref.Context().Tag(tag)
|
||||
|
||||
return remote.Tag(dst, desc, o.Remote...)
|
||||
}
|
33
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/legacy/config.go
generated
vendored
Normal file
33
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/legacy/config.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2019 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 legacy
|
||||
|
||||
import (
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
)
|
||||
|
||||
// LayerConfigFile is the configuration file that holds the metadata describing
|
||||
// a v1 layer. See:
|
||||
// https://github.com/moby/moby/blob/master/image/spec/v1.md
|
||||
type LayerConfigFile struct {
|
||||
v1.ConfigFile
|
||||
|
||||
ContainerConfig v1.Config `json:"container_config,omitempty"`
|
||||
|
||||
ID string `json:"id,omitempty"`
|
||||
Parent string `json:"parent,omitempty"`
|
||||
Throwaway bool `json:"throwaway,omitempty"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
}
|
18
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/legacy/doc.go
generated
vendored
Normal file
18
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/legacy/doc.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2019 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 legacy provides functionality to work with docker images in the v1
|
||||
// format.
|
||||
// See: https://github.com/moby/moby/blob/master/image/spec/v1.md
|
||||
package legacy
|
6
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/legacy/tarball/README.md
generated
vendored
Normal file
6
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/legacy/tarball/README.md
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# `legacy/tarball`
|
||||
|
||||
[](https://godoc.org/github.com/google/go-containerregistry/pkg/legacy/tarball)
|
||||
|
||||
This package implements support for writing legacy tarballs, as described
|
||||
[here](https://github.com/moby/moby/blob/749d90e10f989802638ae542daf54257f3bf71f2/image/spec/v1.2.md#combined-image-json--filesystem-changeset-format).
|
18
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/legacy/tarball/doc.go
generated
vendored
Normal file
18
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/legacy/tarball/doc.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2019 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 tarball provides facilities for writing v1 docker images
|
||||
// (https://github.com/moby/moby/blob/master/image/spec/v1.md) from/to a tarball
|
||||
// on-disk.
|
||||
package tarball
|
373
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/legacy/tarball/write.go
generated
vendored
Normal file
373
src/cmd/linuxkit/vendor/github.com/google/go-containerregistry/pkg/legacy/tarball/write.go
generated
vendored
Normal file
@ -0,0 +1,373 @@
|
||||
// Copyright 2019 Google LLC All Rights Reserved.
|
||||
//
|
||||
// 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 tarball
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/legacy"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/partial"
|
||||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||
)
|
||||
|
||||
// repositoriesTarDescriptor represents the repositories file inside a `docker save` tarball.
|
||||
type repositoriesTarDescriptor map[string]map[string]string
|
||||
|
||||
// v1Layer represents a layer with metadata needed by the v1 image spec https://github.com/moby/moby/blob/master/image/spec/v1.md.
|
||||
type v1Layer struct {
|
||||
// config is the layer metadata.
|
||||
config *legacy.LayerConfigFile
|
||||
// layer is the v1.Layer object this v1Layer represents.
|
||||
layer v1.Layer
|
||||
}
|
||||
|
||||
// json returns the raw bytes of the json metadata of the given v1Layer.
|
||||
func (l *v1Layer) json() ([]byte, error) {
|
||||
return json.Marshal(l.config)
|
||||
}
|
||||
|
||||
// version returns the raw bytes of the "VERSION" file of the given v1Layer.
|
||||
func (l *v1Layer) version() []byte {
|
||||
return []byte("1.0")
|
||||
}
|
||||
|
||||
// v1LayerID computes the v1 image format layer id for the given v1.Layer with the given v1 parent ID and raw image config.
|
||||
func v1LayerID(layer v1.Layer, parentID string, rawConfig []byte) (string, error) {
|
||||
d, err := layer.Digest()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to get layer digest to generate v1 layer ID: %w", err)
|
||||
}
|
||||
s := fmt.Sprintf("%s %s", d.Hex, parentID)
|
||||
if len(rawConfig) != 0 {
|
||||
s = fmt.Sprintf("%s %s", s, string(rawConfig))
|
||||
}
|
||||
rawDigest := sha256.Sum256([]byte(s))
|
||||
return hex.EncodeToString(rawDigest[:]), nil
|
||||
}
|
||||
|
||||
// newTopV1Layer creates a new v1Layer for a layer other than the top layer in a v1 image tarball.
|
||||
func newV1Layer(layer v1.Layer, parent *v1Layer, history v1.History) (*v1Layer, error) {
|
||||
parentID := ""
|
||||
if parent != nil {
|
||||
parentID = parent.config.ID
|
||||
}
|
||||
id, err := v1LayerID(layer, parentID, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to generate v1 layer ID: %w", err)
|
||||
}
|
||||
result := &v1Layer{
|
||||
layer: layer,
|
||||
config: &legacy.LayerConfigFile{
|
||||
ConfigFile: v1.ConfigFile{
|
||||
Created: history.Created,
|
||||
Author: history.Author,
|
||||
},
|
||||
ContainerConfig: v1.Config{
|
||||
Cmd: []string{history.CreatedBy},
|
||||
},
|
||||
ID: id,
|
||||
Parent: parentID,
|
||||
Throwaway: history.EmptyLayer,
|
||||
Comment: history.Comment,
|
||||
},
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// newTopV1Layer creates a new v1Layer for the top layer in a v1 image tarball.
|
||||
func newTopV1Layer(layer v1.Layer, parent *v1Layer, history v1.History, imgConfig *v1.ConfigFile, rawConfig []byte) (*v1Layer, error) {
|
||||
result, err := newV1Layer(layer, parent, history)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := v1LayerID(layer, result.config.Parent, rawConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to generate v1 layer ID for top layer: %w", err)
|
||||
}
|
||||
result.config.ID = id
|
||||
result.config.Architecture = imgConfig.Architecture
|
||||
result.config.Container = imgConfig.Container
|
||||
result.config.DockerVersion = imgConfig.DockerVersion
|
||||
result.config.OS = imgConfig.OS
|
||||
result.config.Config = imgConfig.Config
|
||||
result.config.Created = imgConfig.Created
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// splitTag splits the given tagged image name <registry>/<repository>:<tag>
|
||||
// into <registry>/<repository> and <tag>.
|
||||
func splitTag(name string) (string, string) {
|
||||
// Split on ":"
|
||||
parts := strings.Split(name, ":")
|
||||
// Verify that we aren't confusing a tag for a hostname w/ port for the purposes of weak validation.
|
||||
if len(parts) > 1 && !strings.Contains(parts[len(parts)-1], "/") {
|
||||
base := strings.Join(parts[:len(parts)-1], ":")
|
||||
tag := parts[len(parts)-1]
|
||||
return base, tag
|
||||
}
|
||||
return name, ""
|
||||
}
|
||||
|
||||
// addTags adds the given image tags to the given "repositories" file descriptor in a v1 image tarball.
|
||||
func addTags(repos repositoriesTarDescriptor, tags []string, topLayerID string) {
|
||||
for _, t := range tags {
|
||||
base, tag := splitTag(t)
|
||||
tagToID, ok := repos[base]
|
||||
if !ok {
|
||||
tagToID = make(map[string]string)
|
||||
repos[base] = tagToID
|
||||
}
|
||||
tagToID[tag] = topLayerID
|
||||
}
|
||||
}
|
||||
|
||||
// updateLayerSources updates the given layer digest to descriptor map with the descriptor of the given layer in the given image if it's an undistributable layer.
|
||||
func updateLayerSources(layerSources map[v1.Hash]v1.Descriptor, layer v1.Layer, img v1.Image) error {
|
||||
d, err := layer.Digest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Add to LayerSources if it's a foreign layer.
|
||||
desc, err := partial.BlobDescriptor(img, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !desc.MediaType.IsDistributable() {
|
||||
diffid, err := partial.BlobToDiffID(img, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
layerSources[diffid] = *desc
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write is a wrapper to write a single image in V1 format and tag to a tarball.
|
||||
func Write(ref name.Reference, img v1.Image, w io.Writer) error {
|
||||
return MultiWrite(map[name.Reference]v1.Image{ref: img}, w)
|
||||
}
|
||||
|
||||
// filterEmpty filters out the history corresponding to empty layers from the
|
||||
// given history.
|
||||
func filterEmpty(h []v1.History) []v1.History {
|
||||
result := []v1.History{}
|
||||
for _, i := range h {
|
||||
if i.EmptyLayer {
|
||||
continue
|
||||
}
|
||||
result = append(result, i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// MultiWrite writes the contents of each image to the provided reader, in the V1 image tarball format.
|
||||
// The contents are written in the following format:
|
||||
// One manifest.json file at the top level containing information about several images.
|
||||
// One repositories file mapping from the image <registry>/<repo name> to <tag> to the id of the top most layer.
|
||||
// For every layer, a directory named with the layer ID is created with the following contents:
|
||||
// layer.tar - The uncompressed layer tarball.
|
||||
// <layer id>.json- Layer metadata json.
|
||||
// VERSION- Schema version string. Always set to "1.0".
|
||||
// One file for the config blob, named after its SHA.
|
||||
func MultiWrite(refToImage map[name.Reference]v1.Image, w io.Writer) error {
|
||||
tf := tar.NewWriter(w)
|
||||
defer tf.Close()
|
||||
|
||||
sortedImages, imageToTags := dedupRefToImage(refToImage)
|
||||
var m tarball.Manifest
|
||||
repos := make(repositoriesTarDescriptor)
|
||||
|
||||
seenLayerIDs := make(map[string]struct{})
|
||||
for _, img := range sortedImages {
|
||||
tags := imageToTags[img]
|
||||
|
||||
// Write the config.
|
||||
cfgName, err := img.ConfigName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfgFileName := fmt.Sprintf("%s.json", cfgName.Hex)
|
||||
cfgBlob, err := img.RawConfigFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeTarEntry(tf, cfgFileName, bytes.NewReader(cfgBlob), int64(len(cfgBlob))); err != nil {
|
||||
return err
|
||||
}
|
||||
cfg, err := img.ConfigFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Store foreign layer info.
|
||||
layerSources := make(map[v1.Hash]v1.Descriptor)
|
||||
|
||||
// Write the layers.
|
||||
layers, err := img.Layers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
history := filterEmpty(cfg.History)
|
||||
// Create a blank config history if the config didn't have a history.
|
||||
if len(history) == 0 && len(layers) != 0 {
|
||||
history = make([]v1.History, len(layers))
|
||||
} else if len(layers) != len(history) {
|
||||
return fmt.Errorf("image config had layer history which did not match the number of layers, got len(history)=%d, len(layers)=%d, want len(history)=len(layers)", len(history), len(layers))
|
||||
}
|
||||
layerFiles := make([]string, len(layers))
|
||||
var prev *v1Layer
|
||||
for i, l := range layers {
|
||||
if err := updateLayerSources(layerSources, l, img); err != nil {
|
||||
return fmt.Errorf("unable to update image metadata to include undistributable layer source information: %w", err)
|
||||
}
|
||||
var cur *v1Layer
|
||||
if i < (len(layers) - 1) {
|
||||
cur, err = newV1Layer(l, prev, history[i])
|
||||
} else {
|
||||
cur, err = newTopV1Layer(l, prev, history[i], cfg, cfgBlob)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
layerFiles[i] = fmt.Sprintf("%s/layer.tar", cur.config.ID)
|
||||
if _, ok := seenLayerIDs[cur.config.ID]; ok {
|
||||
prev = cur
|
||||
continue
|
||||
}
|
||||
seenLayerIDs[cur.config.ID] = struct{}{}
|
||||
|
||||
// If the v1.Layer implements UncompressedSize efficiently, use that
|
||||
// for the tar header. Otherwise, this iterates over Uncompressed().
|
||||
// NOTE: If using a streaming layer, this may consume the layer.
|
||||
size, err := partial.UncompressedSize(l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u, err := l.Uncompressed()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer u.Close()
|
||||
if err := writeTarEntry(tf, layerFiles[i], u, size); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
j, err := cur.json()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeTarEntry(tf, fmt.Sprintf("%s/json", cur.config.ID), bytes.NewReader(j), int64(len(j))); err != nil {
|
||||
return err
|
||||
}
|
||||
v := cur.version()
|
||||
if err := writeTarEntry(tf, fmt.Sprintf("%s/VERSION", cur.config.ID), bytes.NewReader(v), int64(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
prev = cur
|
||||
}
|
||||
|
||||
// Generate the tar descriptor and write it.
|
||||
m = append(m, tarball.Descriptor{
|
||||
Config: cfgFileName,
|
||||
RepoTags: tags,
|
||||
Layers: layerFiles,
|
||||
LayerSources: layerSources,
|
||||
})
|
||||
// prev should be the top layer here. Use it to add the image tags
|
||||
// to the tarball repositories file.
|
||||
addTags(repos, tags, prev.config.ID)
|
||||
}
|
||||
|
||||
mBytes, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := writeTarEntry(tf, "manifest.json", bytes.NewReader(mBytes), int64(len(mBytes))); err != nil {
|
||||
return err
|
||||
}
|
||||
reposBytes, err := json.Marshal(&repos)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeTarEntry(tf, "repositories", bytes.NewReader(reposBytes), int64(len(reposBytes))); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func dedupRefToImage(refToImage map[name.Reference]v1.Image) ([]v1.Image, map[v1.Image][]string) {
|
||||
imageToTags := make(map[v1.Image][]string)
|
||||
|
||||
for ref, img := range refToImage {
|
||||
if tag, ok := ref.(name.Tag); ok {
|
||||
if tags, ok := imageToTags[img]; ok && tags != nil {
|
||||
imageToTags[img] = append(tags, tag.String())
|
||||
} else {
|
||||
imageToTags[img] = []string{tag.String()}
|
||||
}
|
||||
} else {
|
||||
if _, ok := imageToTags[img]; !ok {
|
||||
imageToTags[img] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Force specific order on tags
|
||||
imgs := []v1.Image{}
|
||||
for img, tags := range imageToTags {
|
||||
sort.Strings(tags)
|
||||
imgs = append(imgs, img)
|
||||
}
|
||||
|
||||
sort.Slice(imgs, func(i, j int) bool {
|
||||
cfI, err := imgs[i].ConfigName()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
cfJ, err := imgs[j].ConfigName()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return cfI.Hex < cfJ.Hex
|
||||
})
|
||||
|
||||
return imgs, imageToTags
|
||||
}
|
||||
|
||||
// Writes a file to the provided writer with a corresponding tar header
|
||||
func writeTarEntry(tf *tar.Writer, path string, r io.Reader, size int64) error {
|
||||
hdr := &tar.Header{
|
||||
Mode: 0644,
|
||||
Typeflag: tar.TypeReg,
|
||||
Size: size,
|
||||
Name: path,
|
||||
}
|
||||
if err := tf.WriteHeader(hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(tf, r)
|
||||
return err
|
||||
}
|
5
src/cmd/linuxkit/vendor/modules.txt
vendored
5
src/cmd/linuxkit/vendor/modules.txt
vendored
@ -261,7 +261,6 @@ github.com/docker/go-connections/tlsconfig
|
||||
github.com/docker/go-units
|
||||
# github.com/estesp/manifest-tool/v2 v2.0.7-0.20230216152337-24a86fc0b513
|
||||
## explicit; go 1.19
|
||||
github.com/estesp/manifest-tool/v2/pkg/util
|
||||
# github.com/felixge/httpsnoop v1.0.2
|
||||
## explicit; go 1.13
|
||||
github.com/felixge/httpsnoop
|
||||
@ -314,11 +313,15 @@ github.com/google/go-cmp/cmp/internal/value
|
||||
github.com/google/go-containerregistry/internal/and
|
||||
github.com/google/go-containerregistry/internal/estargz
|
||||
github.com/google/go-containerregistry/internal/gzip
|
||||
github.com/google/go-containerregistry/internal/legacy
|
||||
github.com/google/go-containerregistry/internal/redact
|
||||
github.com/google/go-containerregistry/internal/retry
|
||||
github.com/google/go-containerregistry/internal/retry/wait
|
||||
github.com/google/go-containerregistry/internal/verify
|
||||
github.com/google/go-containerregistry/pkg/authn
|
||||
github.com/google/go-containerregistry/pkg/crane
|
||||
github.com/google/go-containerregistry/pkg/legacy
|
||||
github.com/google/go-containerregistry/pkg/legacy/tarball
|
||||
github.com/google/go-containerregistry/pkg/logs
|
||||
github.com/google/go-containerregistry/pkg/name
|
||||
github.com/google/go-containerregistry/pkg/v1
|
||||
|
Loading…
Reference in New Issue
Block a user