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 <dmuel...@suse.com>
+
+- 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/goreleaser-action@v4.2.0
         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 ++++++

Reply via email to