mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 17:26:28 +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"
|
"fmt"
|
||||||
|
|
||||||
"github.com/google/go-containerregistry/pkg/authn"
|
"github.com/google/go-containerregistry/pkg/authn"
|
||||||
|
"github.com/google/go-containerregistry/pkg/crane"
|
||||||
namepkg "github.com/google/go-containerregistry/pkg/name"
|
namepkg "github.com/google/go-containerregistry/pkg/name"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||||
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/util"
|
"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.
|
Long: `Tag a package in a remote registry with another tag, without downloading or pulling.
|
||||||
Will simply tag using the identical descriptor.
|
Will simply tag using the identical descriptor.
|
||||||
First argument is "from" tag, second is "to" tag.
|
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),
|
Args: cobra.ExactArgs(2),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
var finalErr error
|
||||||
from := args[0]
|
from := args[0]
|
||||||
to := args[1]
|
to := args[1]
|
||||||
remoteOptions := []remote.Option{remote.WithAuthFromKeychain(authn.DefaultKeychain)}
|
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)
|
log.Infof("image %s already exists in the registry, but is different from %s, overwriting", toFullname, fromFullname)
|
||||||
}
|
}
|
||||||
toTag, err := namepkg.NewTag(toFullname)
|
// see if they are from the same sources
|
||||||
if err != nil {
|
if fromRef.Context().String() == toRef.Context().String() {
|
||||||
return err
|
toTag, err := namepkg.NewTag(toFullname)
|
||||||
}
|
if err != nil {
|
||||||
if err := remote.Tag(toTag, fromDesc, remoteOptions...); err != nil {
|
return err
|
||||||
return fmt.Errorf("error tagging image %s as %s: %v", fromFullname, toFullname, 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")
|
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/docker/go-units
|
||||||
# github.com/estesp/manifest-tool/v2 v2.0.7-0.20230216152337-24a86fc0b513
|
# github.com/estesp/manifest-tool/v2 v2.0.7-0.20230216152337-24a86fc0b513
|
||||||
## explicit; go 1.19
|
## explicit; go 1.19
|
||||||
github.com/estesp/manifest-tool/v2/pkg/util
|
|
||||||
# github.com/felixge/httpsnoop v1.0.2
|
# github.com/felixge/httpsnoop v1.0.2
|
||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
github.com/felixge/httpsnoop
|
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/and
|
||||||
github.com/google/go-containerregistry/internal/estargz
|
github.com/google/go-containerregistry/internal/estargz
|
||||||
github.com/google/go-containerregistry/internal/gzip
|
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/redact
|
||||||
github.com/google/go-containerregistry/internal/retry
|
github.com/google/go-containerregistry/internal/retry
|
||||||
github.com/google/go-containerregistry/internal/retry/wait
|
github.com/google/go-containerregistry/internal/retry/wait
|
||||||
github.com/google/go-containerregistry/internal/verify
|
github.com/google/go-containerregistry/internal/verify
|
||||||
github.com/google/go-containerregistry/pkg/authn
|
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/logs
|
||||||
github.com/google/go-containerregistry/pkg/name
|
github.com/google/go-containerregistry/pkg/name
|
||||||
github.com/google/go-containerregistry/pkg/v1
|
github.com/google/go-containerregistry/pkg/v1
|
||||||
|
Loading…
Reference in New Issue
Block a user