Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package go-containerregistry for
openSUSE:Factory checked in at 2023-12-28 23:02:52
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/go-containerregistry (Old)
and /work/SRC/openSUSE:Factory/.go-containerregistry.new.28375 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "go-containerregistry"
Thu Dec 28 23:02:52 2023 rev:5 rq:1135385 version:0.17.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/go-containerregistry/go-containerregistry.changes
2023-11-26 19:38:09.612048008 +0100
+++
/work/SRC/openSUSE:Factory/.go-containerregistry.new.28375/go-containerregistry.changes
2023-12-28 23:04:36.673345163 +0100
@@ -1,0 +2,13 @@
+Wed Dec 27 21:21:47 UTC 2023 - Dirk Müller <[email protected]>
+
+- update to 0.17.0:
+ * Validate index architectures match children
+ * Set Content-Length for blob uploads
+ * Don't wrap DefaultKeychain with refreshes
+ * Build releases with Go 1.21
+ * fix: mimic oci-layout in diskblobhandler
+ * tag: add command explanation to the long help
+ * feat: implement gc command
+ * feat: allow port and disk path to be overriden
+
+-------------------------------------------------------------------
Old:
----
go-containerregistry-0.16.1.tar.gz
New:
----
go-containerregistry-0.17.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ go-containerregistry.spec ++++++
--- /var/tmp/diff_new_pack.ajCo6G/_old 2023-12-28 23:04:37.421372502 +0100
+++ /var/tmp/diff_new_pack.ajCo6G/_new 2023-12-28 23:04:37.425372648 +0100
@@ -17,9 +17,8 @@
# nodebuginfo
-%global goipath github.com/google/go-containerregistry
Name: go-containerregistry
-Version: 0.16.1
+Version: 0.17.0
Release: 0
Summary: Container Library and tools for working with container
registries
License: Apache-2.0
@@ -28,7 +27,7 @@
Source:
https://github.com/google/go-containerregistry/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
Source1: vendor.tar.gz
BuildRequires: golang-packaging
-BuildRequires: golang(API) = 1.20
+BuildRequires: golang(API) = 1.21
Conflicts: distribution-registry
%description
@@ -71,17 +70,18 @@
%autopatch -p1
%build
-%{goprep} %{goipath}
-
-export CGO_ENABLED=0
-
-%{gobuild} -mod vendor ./...
+for i in crane gcrane registry; do
+ go build -mod=vendor -buildmode=pie -trimpath ./cmd/$i
+done
%install
-%{goinstall}
+find -name crane
+for bin in crane gcrane registry; do
+ install $bin -D %{buildroot}/%{_bindir}/$bin
+done
# "only one tool per thing" SLE15 policy conflicts
%if 0%{?suse_version} && %{?suse_version} < 1550
-rm -v %{buildroot}/%{_bindir}/{registry,help}
+rm -v %{buildroot}/%{_bindir}/registry
%endif
%if %{?suse_version} > 1500
@@ -89,7 +89,6 @@
%license LICENSE
%doc README.md
%{_bindir}/registry
-%exclude %{_bindir}/help
%endif
%files -n crane
++++++ go-containerregistry-0.16.1.tar.gz -> go-containerregistry-0.17.0.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/go-containerregistry-0.16.1/.gitattributes
new/go-containerregistry-0.17.0/.gitattributes
--- old/go-containerregistry-0.16.1/.gitattributes 2023-08-02
22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/.gitattributes 2023-11-29
22:32:21.000000000 +0100
@@ -5,3 +5,4 @@
**/zz_deepcopy_generated.go linguist-generated=true
cmd/crane/doc/crane*.md linguist-generated=true
go.sum linguist-generated=true
+**/testdata/** ignore-lint=true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/.github/workflows/release.yml
new/go-containerregistry-0.17.0/.github/workflows/release.yml
--- old/go-containerregistry-0.16.1/.github/workflows/release.yml
2023-08-02 22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/.github/workflows/release.yml
2023-11-29 22:32:21.000000000 +0100
@@ -15,7 +15,7 @@
run: git fetch --prune --unshallow
- uses: actions/setup-go@v4
with:
- go-version: 1.18
+ go-version: 1.21
check-latest: true
- uses: goreleaser/[email protected]
id: run-goreleaser
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/go-containerregistry-0.16.1/cmd/crane/cmd/gc.go
new/go-containerregistry-0.17.0/cmd/crane/cmd/gc.go
--- old/go-containerregistry-0.16.1/cmd/crane/cmd/gc.go 1970-01-01
01:00:00.000000000 +0100
+++ new/go-containerregistry-0.17.0/cmd/crane/cmd/gc.go 2023-11-29
22:32:21.000000000 +0100
@@ -0,0 +1,66 @@
+// 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 cmd
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/google/go-containerregistry/pkg/v1/layout"
+ "github.com/spf13/cobra"
+)
+
+func NewCmdLayout() *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "layout",
+ }
+ cmd.AddCommand(newCmdGc())
+ return cmd
+}
+
+// NewCmdGc creates a new cobra.Command for the pull subcommand.
+func newCmdGc() *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "gc OCI-LAYOUT",
+ Short: "Garbage collect unreferenced blobs in a local
oci-layout",
+ Args: cobra.ExactArgs(1),
+ Hidden: true, // TODO: promote to public once theres some milage
+ RunE: func(_ *cobra.Command, args []string) error {
+ path := args[0]
+
+ p, err := layout.FromPath(path)
+
+ if err != nil {
+ return err
+ }
+
+ blobs, err := p.GarbageCollect()
+ if err != nil {
+ return err
+ }
+
+ for _, blob := range blobs {
+ if err := p.RemoveBlob(blob); err != nil {
+ return err
+ }
+ fmt.Fprintf(os.Stderr, "garbage collecting:
%s\n", blob.String())
+ }
+
+ return nil
+ },
+ }
+
+ return cmd
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/go-containerregistry-0.16.1/cmd/crane/cmd/root.go
new/go-containerregistry-0.17.0/cmd/crane/cmd/root.go
--- old/go-containerregistry-0.16.1/cmd/crane/cmd/root.go 2023-08-02
22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/cmd/crane/cmd/root.go 2023-11-29
22:32:21.000000000 +0100
@@ -129,7 +129,8 @@
NewCmdTag(&options),
NewCmdValidate(&options),
NewCmdVersion(),
- newCmdRegistry(),
+ NewCmdRegistry(),
+ NewCmdLayout(),
)
root.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false,
"Enable debug logs")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/go-containerregistry-0.16.1/cmd/crane/cmd/serve.go
new/go-containerregistry-0.17.0/cmd/crane/cmd/serve.go
--- old/go-containerregistry-0.16.1/cmd/crane/cmd/serve.go 2023-08-02
22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/cmd/crane/cmd/serve.go 2023-11-29
22:32:21.000000000 +0100
@@ -28,7 +28,7 @@
"github.com/google/go-containerregistry/pkg/registry"
)
-func newCmdRegistry() *cobra.Command {
+func NewCmdRegistry() *cobra.Command {
cmd := &cobra.Command{
Use: "registry",
}
@@ -37,15 +37,16 @@
}
func newCmdServe() *cobra.Command {
- var disk bool
+ var address, disk string
+ var blobsToDisk bool
cmd := &cobra.Command{
Use: "serve",
- Short: "Serve an in-memory registry implementation",
- Long: `This sub-command serves an in-memory registry
implementation on an automatically chosen port (or $PORT)
+ Short: "Serve a registry implementation",
+ Long: `This sub-command serves a registry implementation on an
automatically chosen port (:0), $PORT or --address
The command blocks while the server accepts pushes and pulls.
-Contents are only stored in memory, and when the process exits, pushed data is
lost.`,
+Contents are can be stored in memory (when the process exits, pushed data is
lost.), and disk (--disk).`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
@@ -54,7 +55,12 @@
if port == "" {
port = "0"
}
- listener, err := net.Listen("tcp", ":"+port)
+ listenOn := ":" + port
+ if address != "" {
+ listenOn = address
+ }
+
+ listener, err := net.Listen("tcp", listenOn)
if err != nil {
log.Fatalln(err)
}
@@ -62,10 +68,21 @@
port = fmt.Sprintf("%d", porti)
bh := registry.NewInMemoryBlobHandler()
- if disk {
- tmp := os.TempDir()
- log.Printf("storing blobs in %s", tmp)
- bh = registry.NewDiskBlobHandler(tmp)
+
+ diskp := disk
+ if cmd.Flags().Changed("blobs-to-disk") {
+ if disk != "" {
+ return fmt.Errorf("--disk and
--blobs-to-disk can't be used together")
+ }
+ diskp, err = os.MkdirTemp(os.TempDir(),
"craneregistry*")
+ if err != nil {
+ return err
+ }
+ }
+
+ if diskp != "" {
+ log.Printf("storing blobs in %s", diskp)
+ bh = registry.NewDiskBlobHandler(diskp)
}
s := &http.Server{
@@ -89,7 +106,12 @@
return nil
},
}
- cmd.Flags().BoolVar(&disk, "blobs-to-disk", false, "Store blobs on
disk")
+ // TODO: remove --blobs-to-disk in a future release.
+ cmd.Flags().BoolVarP(&blobsToDisk, "blobs-to-disk", "", false, "Store
blobs on disk on tmpdir")
cmd.Flags().MarkHidden("blobs-to-disk")
+ cmd.Flags().MarkDeprecated("blobs-to-disk", "and will stop working in a
future release. use --disk=$(mktemp -d) instead.")
+ cmd.Flags().StringVarP(&disk, "disk", "", "", "Path to a directory
where blobs will be stored")
+ cmd.Flags().StringVar(&address, "address", "", "Address to listen on")
+
return cmd
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/go-containerregistry-0.16.1/cmd/crane/cmd/tag.go
new/go-containerregistry-0.17.0/cmd/crane/cmd/tag.go
--- old/go-containerregistry-0.16.1/cmd/crane/cmd/tag.go 2023-08-02
22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/cmd/crane/cmd/tag.go 2023-11-29
22:32:21.000000000 +0100
@@ -24,7 +24,9 @@
return &cobra.Command{
Use: "tag IMG TAG",
Short: "Efficiently tag a remote image",
- Long: `This differs slightly from the "copy" command in a
couple subtle ways:
+ Long: `Tag remote image without downloading it.
+
+This differs slightly from the "copy" command in a couple subtle ways:
1. You don't have to specify the entire repository for the tag you're adding.
For example, these two commands are functionally equivalent:
` + "```" + `
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/cmd/crane/cmd/validate.go
new/go-containerregistry-0.17.0/cmd/crane/cmd/validate.go
--- old/go-containerregistry-0.16.1/cmd/crane/cmd/validate.go 2023-08-02
22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/cmd/crane/cmd/validate.go 2023-11-29
22:32:21.000000000 +0100
@@ -18,7 +18,6 @@
"fmt"
"github.com/google/go-containerregistry/pkg/crane"
- v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/tarball"
"github.com/google/go-containerregistry/pkg/v1/validate"
"github.com/spf13/cobra"
@@ -36,28 +35,56 @@
Short: "Validate that an image is well-formed",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
- for flag, maker := range map[string]func(string,
...crane.Option) (v1.Image, error){
- tarballPath: makeTarball,
- remoteRef: crane.Pull,
- } {
- if flag == "" {
- continue
- }
- img, err := maker(flag, *options...)
+ if tarballPath != "" {
+ img, err := tarball.ImageFromPath(tarballPath,
nil)
if err != nil {
- return fmt.Errorf("failed to read image
%s: %w", flag, err)
+ return fmt.Errorf("failed to read image
%s: %w", tarballPath, err)
}
-
opt := []validate.Option{}
if fast {
opt = append(opt, validate.Fast)
}
if err := validate.Image(img, opt...); err !=
nil {
- fmt.Fprintf(cmd.OutOrStdout(), "FAIL:
%s: %v\n", flag, err)
+ fmt.Fprintf(cmd.OutOrStdout(), "FAIL:
%s: %v\n", tarballPath, err)
return err
}
- fmt.Fprintf(cmd.OutOrStdout(), "PASS: %s\n",
flag)
+ fmt.Fprintf(cmd.OutOrStdout(), "PASS: %s\n",
tarballPath)
+ }
+
+ if remoteRef != "" {
+ rmt, err := crane.Get(remoteRef, *options...)
+ if err != nil {
+ return fmt.Errorf("failed to read image
%s: %w", remoteRef, err)
+ }
+
+ o := crane.GetOptions(*options...)
+
+ opt := []validate.Option{}
+ if fast {
+ opt = append(opt, validate.Fast)
+ }
+ if rmt.MediaType.IsIndex() && o.Platform == nil
{
+ idx, err := rmt.ImageIndex()
+ if err != nil {
+ return fmt.Errorf("reading
index: %w", err)
+ }
+ if err := validate.Index(idx, opt...);
err != nil {
+ fmt.Fprintf(cmd.OutOrStdout(),
"FAIL: %s: %v\n", remoteRef, err)
+ return err
+ }
+ } else {
+ img, err := rmt.Image()
+ if err != nil {
+ return fmt.Errorf("reading
image: %w", err)
+ }
+ if err := validate.Image(img, opt...);
err != nil {
+ fmt.Fprintf(cmd.OutOrStdout(),
"FAIL: %s: %v\n", remoteRef, err)
+ return err
+ }
+ }
+ fmt.Fprintf(cmd.OutOrStdout(), "PASS: %s\n",
remoteRef)
}
+
return nil
},
}
@@ -67,7 +94,3 @@
return validateCmd
}
-
-func makeTarball(path string, _ ...crane.Option) (v1.Image, error) {
- return tarball.ImageFromPath(path, nil)
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/cmd/crane/doc/crane_registry.md
new/go-containerregistry-0.17.0/cmd/crane/doc/crane_registry.md
--- old/go-containerregistry-0.16.1/cmd/crane/doc/crane_registry.md
2023-08-02 22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/cmd/crane/doc/crane_registry.md
2023-11-29 22:32:21.000000000 +0100
@@ -20,5 +20,5 @@
### SEE ALSO
* [crane](crane.md) - Crane is a tool for managing container images
-* [crane registry serve](crane_registry_serve.md) - Serve an in-memory
registry implementation
+* [crane registry serve](crane_registry_serve.md) - Serve a registry
implementation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/cmd/crane/doc/crane_registry_serve.md
new/go-containerregistry-0.17.0/cmd/crane/doc/crane_registry_serve.md
--- old/go-containerregistry-0.16.1/cmd/crane/doc/crane_registry_serve.md
2023-08-02 22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/cmd/crane/doc/crane_registry_serve.md
2023-11-29 22:32:21.000000000 +0100
@@ -1,14 +1,14 @@
## crane registry serve
-Serve an in-memory registry implementation
+Serve a registry implementation
### Synopsis
-This sub-command serves an in-memory registry implementation on an
automatically chosen port (or $PORT)
+This sub-command serves a registry implementation on an automatically chosen
port (:0), $PORT or --address
The command blocks while the server accepts pushes and pulls.
-Contents are only stored in memory, and when the process exits, pushed data is
lost.
+Contents are can be stored in memory (when the process exits, pushed data is
lost.), and disk (--disk).
```
crane registry serve [flags]
@@ -17,7 +17,9 @@
### Options
```
- -h, --help help for serve
+ --address string Address to listen on
+ --disk string Path to a directory where blobs will be stored
+ -h, --help help for serve
```
### Options inherited from parent commands
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/cmd/crane/doc/crane_tag.md
new/go-containerregistry-0.17.0/cmd/crane/doc/crane_tag.md
--- old/go-containerregistry-0.16.1/cmd/crane/doc/crane_tag.md 2023-08-02
22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/cmd/crane/doc/crane_tag.md 2023-11-29
22:32:21.000000000 +0100
@@ -4,6 +4,8 @@
### Synopsis
+Tag remote image without downloading it.
+
This differs slightly from the "copy" command in a couple subtle ways:
1. You don't have to specify the entire repository for the tag you're adding.
For example, these two commands are functionally equivalent:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/go-containerregistry-0.16.1/pkg/authn/keychain.go
new/go-containerregistry-0.17.0/pkg/authn/keychain.go
--- old/go-containerregistry-0.16.1/pkg/authn/keychain.go 2023-08-02
22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/pkg/authn/keychain.go 2023-11-29
22:32:21.000000000 +0100
@@ -53,7 +53,7 @@
var (
// DefaultKeychain implements Keychain by interpreting the docker
config file.
- DefaultKeychain = RefreshingKeychain(&defaultKeychain{}, 5*time.Minute)
+ DefaultKeychain = &defaultKeychain{}
)
const (
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/pkg/registry/blobs_disk.go
new/go-containerregistry-0.17.0/pkg/registry/blobs_disk.go
--- old/go-containerregistry-0.16.1/pkg/registry/blobs_disk.go 2023-08-02
22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/pkg/registry/blobs_disk.go 2023-11-29
22:32:21.000000000 +0100
@@ -30,8 +30,12 @@
func NewDiskBlobHandler(dir string) BlobHandler { return &diskHandler{dir:
dir} }
+func (m *diskHandler) blobHashPath(h v1.Hash) string {
+ return filepath.Join(m.dir, h.Algorithm, h.Hex)
+}
+
func (m *diskHandler) Stat(_ context.Context, _ string, h v1.Hash) (int64,
error) {
- fi, err := os.Stat(filepath.Join(m.dir, h.String()))
+ fi, err := os.Stat(m.blobHashPath(h))
if errors.Is(err, os.ErrNotExist) {
return 0, errNotFound
} else if err != nil {
@@ -40,7 +44,7 @@
return fi.Size(), nil
}
func (m *diskHandler) Get(_ context.Context, _ string, h v1.Hash)
(io.ReadCloser, error) {
- return os.Open(filepath.Join(m.dir, h.String()))
+ return os.Open(m.blobHashPath(h))
}
func (m *diskHandler) Put(_ context.Context, _ string, h v1.Hash, rc
io.ReadCloser) error {
// Put the temp file in the same directory to avoid cross-device
problems
@@ -57,9 +61,11 @@
}(); err != nil {
return err
}
-
- return os.Rename(f.Name(), filepath.Join(m.dir, h.String()))
+ if err := os.MkdirAll(filepath.Join(m.dir, h.Algorithm), os.ModePerm);
err != nil {
+ return err
+ }
+ return os.Rename(f.Name(), m.blobHashPath(h))
}
func (m *diskHandler) Delete(_ context.Context, _ string, h v1.Hash) error {
- return os.Remove(filepath.Join(m.dir, h.String()))
+ return os.Remove(m.blobHashPath(h))
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/pkg/registry/blobs_disk_test.go
new/go-containerregistry-0.17.0/pkg/registry/blobs_disk_test.go
--- old/go-containerregistry-0.16.1/pkg/registry/blobs_disk_test.go
2023-08-02 22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/pkg/registry/blobs_disk_test.go
2023-11-29 22:32:21.000000000 +0100
@@ -15,6 +15,7 @@
package registry_test
import (
+ "fmt"
"net/http/httptest"
"os"
"path/filepath"
@@ -59,7 +60,7 @@
if h, err := img.ConfigName(); err != nil {
t.Fatal(err)
} else {
- want[h.String()] = true
+ want[fmt.Sprintf("%s/%s", h.Algorithm, h.Hex)] = true
}
ls, err := img.Layers()
if err != nil {
@@ -69,7 +70,7 @@
if h, err := l.Digest(); err != nil {
t.Fatal(err)
} else {
- want[h.String()] = true
+ want[fmt.Sprintf("%s/%s", h.Algorithm, h.Hex)] = true
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/go-containerregistry-0.16.1/pkg/v1/layout/gc.go
new/go-containerregistry-0.17.0/pkg/v1/layout/gc.go
--- old/go-containerregistry-0.16.1/pkg/v1/layout/gc.go 1970-01-01
01:00:00.000000000 +0100
+++ new/go-containerregistry-0.17.0/pkg/v1/layout/gc.go 2023-11-29
22:32:21.000000000 +0100
@@ -0,0 +1,137 @@
+// 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.
+
+// This is an EXPERIMENTAL package, and may change in arbitrary ways without
notice.
+package layout
+
+import (
+ "fmt"
+ "io/fs"
+ "path/filepath"
+ "strings"
+
+ v1 "github.com/google/go-containerregistry/pkg/v1"
+)
+
+// GarbageCollect removes unreferenced blobs from the oci-layout
+//
+// This is an experimental api, and not subject to any stability guarantees
+// We may abandon it at any time, without prior notice.
+// Deprecated: Use it at your own risk!
+func (l Path) GarbageCollect() ([]v1.Hash, error) {
+ idx, err := l.ImageIndex()
+ if err != nil {
+ return nil, err
+ }
+ blobsToKeep := map[string]bool{}
+ if err := l.garbageCollectImageIndex(idx, blobsToKeep); err != nil {
+ return nil, err
+ }
+ blobsDir := l.path("blobs")
+ removedBlobs := []v1.Hash{}
+
+ err = filepath.WalkDir(blobsDir, func(path string, d fs.DirEntry, err
error) error {
+ if err != nil {
+ return err
+ }
+
+ if d.IsDir() {
+ return nil
+ }
+
+ rel, err := filepath.Rel(blobsDir, path)
+ if err != nil {
+ return err
+ }
+ hashString := strings.Replace(rel, "/", ":", 1)
+ if present := blobsToKeep[hashString]; !present {
+ h, err := v1.NewHash(hashString)
+ if err != nil {
+ return err
+ }
+ removedBlobs = append(removedBlobs, h)
+ }
+ return nil
+ })
+
+ if err != nil {
+ return nil, err
+ }
+
+ return removedBlobs, nil
+}
+
+func (l Path) garbageCollectImageIndex(index v1.ImageIndex, blobsToKeep
map[string]bool) error {
+ idxm, err := index.IndexManifest()
+ if err != nil {
+ return err
+ }
+
+ h, err := index.Digest()
+ if err != nil {
+ return err
+ }
+
+ blobsToKeep[h.String()] = true
+
+ for _, descriptor := range idxm.Manifests {
+ if descriptor.MediaType.IsImage() {
+ img, err := index.Image(descriptor.Digest)
+ if err != nil {
+ return err
+ }
+ if err := l.garbageCollectImage(img, blobsToKeep); err
!= nil {
+ return err
+ }
+ } else if descriptor.MediaType.IsIndex() {
+ idx, err := index.ImageIndex(descriptor.Digest)
+ if err != nil {
+ return err
+ }
+ if err := l.garbageCollectImageIndex(idx, blobsToKeep);
err != nil {
+ return err
+ }
+ } else {
+ return fmt.Errorf("gc: unknown media type: %s",
descriptor.MediaType)
+ }
+ }
+ return nil
+}
+
+func (l Path) garbageCollectImage(image v1.Image, blobsToKeep map[string]bool)
error {
+ h, err := image.Digest()
+ if err != nil {
+ return err
+ }
+ blobsToKeep[h.String()] = true
+
+ h, err = image.ConfigName()
+ if err != nil {
+ return err
+ }
+ blobsToKeep[h.String()] = true
+
+ ls, err := image.Layers()
+ if err != nil {
+ return err
+ }
+ for _, l := range ls {
+ h, err := l.Digest()
+ if err != nil {
+ return err
+ }
+ blobsToKeep[h.String()] = true
+ }
+ return nil
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/go-containerregistry-0.16.1/pkg/v1/layout/gc_test.go
new/go-containerregistry-0.17.0/pkg/v1/layout/gc_test.go
--- old/go-containerregistry-0.16.1/pkg/v1/layout/gc_test.go 1970-01-01
01:00:00.000000000 +0100
+++ new/go-containerregistry-0.17.0/pkg/v1/layout/gc_test.go 2023-11-29
22:32:21.000000000 +0100
@@ -0,0 +1,96 @@
+// 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 layout
+
+import (
+ "path/filepath"
+ "testing"
+)
+
+var (
+ gcIndexPath = filepath.Join("testdata", "test_gc_index")
+ gcIndexBlobHash =
"sha256:492b89b9dd3cda4596f94916d17f6901455fb8bd7f4c5a2a90df8d39c90f48a0"
+ gcUnknownMediaTypePath = filepath.Join("testdata",
"test_gc_image_unknown_mediatype")
+ gcUnknownMediaTypeErr = "gc: unknown media type:
application/vnd.oci.descriptor.v1+json"
+ gcTestOneImagePath = filepath.Join("testdata",
"test_index_one_image")
+ gcTestIndexMediaTypePath = filepath.Join("testdata",
"test_index_media_type")
+)
+
+func TestGcIndex(t *testing.T) {
+ lp, err := FromPath(gcIndexPath)
+ if err != nil {
+ t.Fatalf("FromPath() = %v", err)
+ }
+
+ removed, err := lp.GarbageCollect()
+ if err != nil {
+ t.Fatalf("GarbageCollect() = %v", err)
+ }
+
+ if len(removed) != 1 {
+ t.Fatalf("expected to have only one gc-able blob")
+ }
+ if removed[0].String() != gcIndexBlobHash {
+ t.Fatalf("wrong blob is gc-ed: expected '%s', got '%s'",
gcIndexBlobHash, removed[0].String())
+ }
+}
+
+func TestGcOneImage(t *testing.T) {
+ lp, err := FromPath(gcTestOneImagePath)
+ if err != nil {
+ t.Fatalf("FromPath() = %v", err)
+ }
+
+ removed, err := lp.GarbageCollect()
+ if err != nil {
+ t.Fatalf("GarbageCollect() = %v", err)
+ }
+
+ if len(removed) != 0 {
+ t.Fatalf("expected to have to gc-able blobs")
+ }
+}
+
+func TestGcIndexMediaType(t *testing.T) {
+ lp, err := FromPath(gcTestIndexMediaTypePath)
+ if err != nil {
+ t.Fatalf("FromPath() = %v", err)
+ }
+
+ removed, err := lp.GarbageCollect()
+ if err != nil {
+ t.Fatalf("GarbageCollect() = %v", err)
+ }
+
+ if len(removed) != 0 {
+ t.Fatalf("expected to have to gc-able blobs")
+ }
+}
+
+func TestGcUnknownMediaType(t *testing.T) {
+ lp, err := FromPath(gcUnknownMediaTypePath)
+ if err != nil {
+ t.Fatalf("FromPath() = %v", err)
+ }
+
+ _, err = lp.GarbageCollect()
+ if err == nil {
+ t.Fatalf("expected GarbageCollect to return err but did not")
+ }
+
+ if err.Error() != gcUnknownMediaTypeErr {
+ t.Fatalf("expected error '%s', got '%s'",
gcUnknownMediaTypeErr, err.Error())
+ }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_image_unknown_mediatype/index.json
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_image_unknown_mediatype/index.json
---
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_image_unknown_mediatype/index.json
1970-01-01 01:00:00.000000000 +0100
+++
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_image_unknown_mediatype/index.json
2023-11-29 22:32:21.000000000 +0100
@@ -0,0 +1,10 @@
+{
+ "schemaVersion": 2,
+ "manifests": [
+ {
+ "mediaType": "application/vnd.oci.descriptor.v1+json",
+ "size": 423,
+ "digest":
"sha256:32589985702551b6c56033bb3334432a0a513bf9d6aceda0f67c42b003850720"
+ }
+ ]
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_image_unknown_mediatype/oci-layout
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_image_unknown_mediatype/oci-layout
---
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_image_unknown_mediatype/oci-layout
1970-01-01 01:00:00.000000000 +0100
+++
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_image_unknown_mediatype/oci-layout
2023-11-29 22:32:21.000000000 +0100
@@ -0,0 +1,3 @@
+{
+ "imageLayoutVersion": "1.0.0"
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5
---
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5
1970-01-01 01:00:00.000000000 +0100
+++
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5
2023-11-29 22:32:21.000000000 +0100
@@ -0,0 +1,13 @@
+{
+ "schemaVersion": 2,
+ "manifests": [
+ {
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
+ "size": 423,
+ "digest":
"sha256:eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650",
+ "annotations": {
+ "org.opencontainers.image.ref.name": "1"
+ }
+ }
+ ]
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/2b29a2b8dea3af91ea7d0154be1da0c92d55ddd098540930fc8d3db7de377fdb
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/2b29a2b8dea3af91ea7d0154be1da0c92d55ddd098540930fc8d3db7de377fdb
---
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/2b29a2b8dea3af91ea7d0154be1da0c92d55ddd098540930fc8d3db7de377fdb
1970-01-01 01:00:00.000000000 +0100
+++
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/2b29a2b8dea3af91ea7d0154be1da0c92d55ddd098540930fc8d3db7de377fdb
2023-11-29 22:32:21.000000000 +0100
@@ -0,0 +1,13 @@
+{
+ "schemaVersion": 2,
+ "manifests": [
+ {
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
+ "size": 423,
+ "digest":
"sha256:eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650",
+ "annotations": {
+ "org.opencontainers.image.ref.name": "4"
+ }
+ }
+ ]
+}
Binary files
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/492b89b9dd3cda4596f94916d17f6901455fb8bd7f4c5a2a90df8d39c90f48a0
and
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/492b89b9dd3cda4596f94916d17f6901455fb8bd7f4c5a2a90df8d39c90f48a0
differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e
---
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e
1970-01-01 01:00:00.000000000 +0100
+++
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e
2023-11-29 22:32:21.000000000 +0100
@@ -0,0 +1 @@
+{"architecture": "amd64", "author": "Bazel", "config": {}, "created":
"1970-01-01T00:00:00Z", "history": [{"author": "Bazel", "created":
"1970-01-01T00:00:00Z", "created_by": "bazel build ..."}], "os": "linux",
"rootfs": {"diff_ids":
["sha256:8897395fd26dc44ad0e2a834335b33198cb41ac4d98dfddf58eced3853fa7b17"],
"type": "layers"}}
Binary files
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/dc52c6e48a1d51a96047b059f16889bc889c4b4c28f3b36b3f93187f62fc0b2b
and
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/dc52c6e48a1d51a96047b059f16889bc889c4b4c28f3b36b3f93187f62fc0b2b
differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650
---
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650
1970-01-01 01:00:00.000000000 +0100
+++
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/blobs/sha256/eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650
2023-11-29 22:32:21.000000000 +0100
@@ -0,0 +1 @@
+{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","size":330,"digest":"sha256:6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e"},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","size":167,"digest":"sha256:dc52c6e48a1d51a96047b059f16889bc889c4b4c28f3b36b3f93187f62fc0b2b"}]}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/index.json
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/index.json
---
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/index.json
1970-01-01 01:00:00.000000000 +0100
+++
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/index.json
2023-11-29 22:32:21.000000000 +0100
@@ -0,0 +1,29 @@
+{
+ "schemaVersion": 2,
+ "manifests": [
+ {
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
+ "size": 423,
+ "digest":
"sha256:eebff607b1628d67459b0596643fc07de70d702eccf030f0bc7bb6fc2b278650",
+ "annotations": {
+ "org.opencontainers.image.ref.name": "1"
+ }
+ },
+ {
+ "mediaType": "application/vnd.oci.image.index.v1+json",
+ "size": 314,
+ "digest":
"sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5",
+ "annotations": {
+ "org.opencontainers.image.ref.name": "3"
+ }
+ },
+ {
+ "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
+ "size": 314,
+ "digest":
"sha256:2b29a2b8dea3af91ea7d0154be1da0c92d55ddd098540930fc8d3db7de377fdb",
+ "annotations": {
+ "org.opencontainers.image.ref.name": "4"
+ }
+ }
+ ]
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/oci-layout
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/oci-layout
---
old/go-containerregistry-0.16.1/pkg/v1/layout/testdata/test_gc_index/oci-layout
1970-01-01 01:00:00.000000000 +0100
+++
new/go-containerregistry-0.17.0/pkg/v1/layout/testdata/test_gc_index/oci-layout
2023-11-29 22:32:21.000000000 +0100
@@ -0,0 +1,3 @@
+{
+ "imageLayoutVersion": "1.0.0"
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/go-containerregistry-0.16.1/pkg/v1/remote/write.go
new/go-containerregistry-0.17.0/pkg/v1/remote/write.go
--- old/go-containerregistry-0.16.1/pkg/v1/remote/write.go 2023-08-02
22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/pkg/v1/remote/write.go 2023-11-29
22:32:21.000000000 +0100
@@ -280,6 +280,11 @@
if _, ok := layer.(*stream.Layer); !ok {
// We can't retry streaming layers.
req.GetBody = getBody
+
+ // If we know the size, set it.
+ if size, err := layer.Size(); err == nil {
+ req.ContentLength = size
+ }
}
req.Header.Set("Content-Type", "application/octet-stream")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/go-containerregistry-0.16.1/pkg/v1/validate/index.go
new/go-containerregistry-0.17.0/pkg/v1/validate/index.go
--- old/go-containerregistry-0.16.1/pkg/v1/validate/index.go 2023-08-02
22:59:06.000000000 +0200
+++ new/go-containerregistry-0.17.0/pkg/v1/validate/index.go 2023-11-29
22:32:21.000000000 +0100
@@ -79,6 +79,9 @@
if err := validateMediaType(img, desc.MediaType); err
!= nil {
errs = append(errs, fmt.Sprintf("failed to
validate image MediaType[%d](%s): %v", i, desc.Digest, err))
}
+ if err := validatePlatform(img, desc.Platform); err !=
nil {
+ errs = append(errs, fmt.Sprintf("failed to
validate image platform[%d](%s): %v", i, desc.Digest, err))
+ }
default:
// Workaround for #819.
if wl, ok := idx.(withLayer); ok {
@@ -173,3 +176,54 @@
return nil
}
+
+func validatePlatform(img v1.Image, want *v1.Platform) error {
+ if want == nil {
+ return nil
+ }
+
+ cf, err := img.ConfigFile()
+ if err != nil {
+ return err
+ }
+
+ got := cf.Platform()
+
+ if got == nil {
+ return fmt.Errorf("config file missing platform fields")
+ }
+
+ if got.Equals(*want) {
+ return nil
+ }
+
+ errs := []string{}
+
+ if got.OS != want.OS {
+ errs = append(errs, fmt.Sprintf("mismatched OS: %s != %s",
got.OS, want.OS))
+ }
+
+ if got.Architecture != want.Architecture {
+ errs = append(errs, fmt.Sprintf("mismatched Architecture: %s !=
%s", got.Architecture, want.Architecture))
+ }
+
+ if got.OSVersion != want.OSVersion {
+ errs = append(errs, fmt.Sprintf("mismatched OSVersion: %s !=
%s", got.OSVersion, want.OSVersion))
+ }
+
+ if got.OSVersion != want.OSVersion {
+ errs = append(errs, fmt.Sprintf("mismatched OSVersion: %s !=
%s", got.OSVersion, want.OSVersion))
+ }
+
+ if len(errs) == 0 {
+ // If we got here, some features might be mismatched. Just add
those...
+ if len(got.Features) != 0 || len(want.Features) != 0 {
+ errs = append(errs, fmt.Sprintf("mismatched Features:
%v, %v", got.Features, want.Features))
+ }
+ if len(got.OSFeatures) != 0 || len(want.OSFeatures) != 0 {
+ errs = append(errs, fmt.Sprintf("mismatched OSFeatures:
%v, %v", got.OSFeatures, want.OSFeatures))
+ }
+ }
+
+ return errors.New(strings.Join(errs, "\n"))
+}
++++++ vendor.tar.gz ++++++