diff --git a/go.mod b/go.mod index eb8c3f350..b09ceef1f 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/containerd/containerd v1.7.2 github.com/containernetworking/cni v1.1.2 github.com/containernetworking/plugins v1.3.0 - github.com/containers/image/v5 v5.26.1-0.20230721030518-80390f7f30d1 + github.com/containers/image/v5 v5.26.1-0.20230726142307-8c387a14f4ac github.com/containers/ocicrypt v1.1.7 github.com/containers/storage v1.48.1-0.20230721123825-4a3a3019d765 github.com/coreos/go-systemd/v22 v22.5.0 @@ -116,7 +116,7 @@ require ( github.com/theupdateframework/go-tuf v0.5.2 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/ulikunitz/xz v0.5.11 // indirect - github.com/vbatts/tar-split v0.11.3 // indirect + github.com/vbatts/tar-split v0.11.5 // indirect github.com/vbauerster/mpb/v8 v8.5.2 // indirect github.com/vishvananda/netns v0.0.4 // indirect go.mongodb.org/mongo-driver v1.11.3 // indirect diff --git a/go.sum b/go.sum index 07f7d47ba..92d0d4f98 100644 --- a/go.sum +++ b/go.sum @@ -5,7 +5,6 @@ github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774 h1:SCbEWT58NSt7 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= @@ -49,8 +48,8 @@ github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl3 github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= github.com/containernetworking/plugins v1.3.0 h1:QVNXMT6XloyMUoO2wUOqWTC1hWFV62Q6mVDp5H1HnjM= github.com/containernetworking/plugins v1.3.0/go.mod h1:Pc2wcedTQQCVuROOOaLBPPxrEXqqXBFt3cZ+/yVg6l0= -github.com/containers/image/v5 v5.26.1-0.20230721030518-80390f7f30d1 h1:KwXetYQJKkzdk3F9M1Y/OsOeF53SkRMVpG6Enmi3cSs= -github.com/containers/image/v5 v5.26.1-0.20230721030518-80390f7f30d1/go.mod h1:q4bDVVLFnYyYp6chHjevV7Ns7PmBQqkpj9mRlvs3f4k= +github.com/containers/image/v5 v5.26.1-0.20230726142307-8c387a14f4ac h1:EQQX+EO+F30H9vJS6vfDXx83Z6OL1YNkO5LN36BtPnM= +github.com/containers/image/v5 v5.26.1-0.20230726142307-8c387a14f4ac/go.mod h1:Zg7m6YHPZRl/wbUDZ6vt+yAyXAjAvALVUelmsIPpMcE= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.1.7 h1:thhNr4fu2ltyGz8aMx8u48Ae0Pnbip3ePP9/mzkZ/3U= @@ -354,7 +353,6 @@ github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= @@ -393,9 +391,8 @@ github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= -github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= -github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= +github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= +github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= github.com/vbauerster/mpb/v8 v8.5.2 h1:zanzt1cZpSEG5uGNYKcv43+97f0IgEnXpuBFaMxKbM0= github.com/vbauerster/mpb/v8 v8.5.2/go.mod h1:YqKyR4ZR6Gd34yD3cDHPMmQxc+uUQMwjgO/LkxiJQ6I= github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= @@ -506,7 +503,6 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/libimage/manifests/manifests.go b/libimage/manifests/manifests.go index 7a51b8423..68f991485 100644 --- a/libimage/manifests/manifests.go +++ b/libimage/manifests/manifests.go @@ -14,6 +14,7 @@ import ( "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/image" "github.com/containers/image/v5/manifest" + "github.com/containers/image/v5/pkg/compression" "github.com/containers/image/v5/signature" "github.com/containers/image/v5/signature/signer" is "github.com/containers/image/v5/storage" @@ -70,6 +71,7 @@ type PushOptions struct { RemoveSignatures bool // true to discard signatures in images ManifestType string // the format to use when saving the list - possible options are oci, v2s1, and v2s2 SourceFilter LookupReferenceFunc // filter the list source + AddCompression []string // add existing instances with requested compression algorithms to manifest list } // Create creates a new list containing information about the specified image, @@ -239,6 +241,10 @@ func (l *list) Push(ctx context.Context, dest types.ImageReference, options Push return nil, "", err } } + compressionVariants, err := prepareAddWithCompression(options.AddCompression) + if err != nil { + return nil, "", err + } copyOptions := &cp.Options{ ImageListSelection: options.ImageListSelection, Instances: options.Instances, @@ -252,6 +258,7 @@ func (l *list) Push(ctx context.Context, dest types.ImageReference, options Push SignBySigstorePrivateKeyFile: options.SignBySigstorePrivateKeyFile, SignSigstorePrivateKeyPassphrase: options.SignSigstorePrivateKeyPassphrase, ForceManifestMIMEType: singleImageManifestType, + EnsureCompressionVariantsExist: compressionVariants, } // Copy whatever we were asked to copy. @@ -266,6 +273,18 @@ func (l *list) Push(ctx context.Context, dest types.ImageReference, options Push return nil, manifestDigest, nil } +func prepareAddWithCompression(variants []string) ([]cp.OptionCompressionVariant, error) { + res := []cp.OptionCompressionVariant{} + for _, name := range variants { + algo, err := compression.AlgorithmByName(name) + if err != nil { + return nil, fmt.Errorf("requested algorithm %s is not supported for replication: %w", name, err) + } + res = append(res, cp.OptionCompressionVariant{Algorithm: algo}) + } + return res, nil +} + // Add adds information about the specified image to the list, computing the // image's manifest's digest, retrieving OS and architecture information from // the image's configuration, and recording the image's reference so that it diff --git a/libimage/manifests/manifests_test.go b/libimage/manifests/manifests_test.go index 3b8b0e400..06b5ba0b0 100644 --- a/libimage/manifests/manifests_test.go +++ b/libimage/manifests/manifests_test.go @@ -333,4 +333,8 @@ func TestPush(t *testing.T) { options.Instances = append(options.Instances, otherListDigest) _, _, err = list.Push(ctx, destRef, options) assert.Nilf(t, err, "list.Push(four specified)") + + options.AddCompression = []string{"zstd"} + _, _, err = list.Push(ctx, destRef, options) + assert.NoError(t, err, "list.Push(with replication for zstd specified)") } diff --git a/vendor/github.com/containers/image/v5/copy/copy.go b/vendor/github.com/containers/image/v5/copy/copy.go index 53ae20cc7..ac0e6f2fa 100644 --- a/vendor/github.com/containers/image/v5/copy/copy.go +++ b/vendor/github.com/containers/image/v5/copy/copy.go @@ -17,6 +17,7 @@ import ( "github.com/containers/image/v5/internal/private" "github.com/containers/image/v5/manifest" "github.com/containers/image/v5/pkg/blobinfocache" + compression "github.com/containers/image/v5/pkg/compression/types" "github.com/containers/image/v5/signature" "github.com/containers/image/v5/signature/signer" "github.com/containers/image/v5/transports" @@ -126,6 +127,21 @@ type Options struct { // Download layer contents with "nondistributable" media types ("foreign" layers) and translate the layer media type // to not indicate "nondistributable". DownloadForeignLayers bool + + // Contains slice of OptionCompressionVariant, where copy will ensure that for each platform + // in the manifest list, a variant with the requested compression will exist. + // Invalid when copying a non-multi-architecture image. That will probably + // change in the future. + EnsureCompressionVariantsExist []OptionCompressionVariant +} + +// OptionCompressionVariant allows to supply information about +// selected compression algorithm and compression level by the +// end-user. Refer to EnsureCompressionVariantsExist to know +// more about its usage. +type OptionCompressionVariant struct { + Algorithm compression.Algorithm + Level *int // Only used when we are creating a new image instance using the specified algorithm, not when the image already contains such an instance } // copier allows us to keep track of diffID values for blobs, and other @@ -250,13 +266,19 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef, } if !multiImage { + if len(options.EnsureCompressionVariantsExist) > 0 { + return nil, fmt.Errorf("EnsureCompressionVariantsExist is not implemented when not creating a multi-architecture image") + } // The simple case: just copy a single image. - single, err := c.copySingleImage(ctx, c.unparsedToplevel, nil, false) + single, err := c.copySingleImage(ctx, c.unparsedToplevel, nil, copySingleImageOptions{requireCompressionFormatMatch: false}) if err != nil { return nil, err } copiedManifest = single.manifest } else if c.options.ImageListSelection == CopySystemImage { + if len(options.EnsureCompressionVariantsExist) > 0 { + return nil, fmt.Errorf("EnsureCompressionVariantsExist is not implemented when not creating a multi-architecture image") + } // This is a manifest list, and we weren't asked to copy multiple images. Choose a single image that // matches the current system to copy, and copy it. mfest, manifestType, err := c.unparsedToplevel.Manifest(ctx) @@ -273,8 +295,7 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef, } logrus.Debugf("Source is a manifest list; copying (only) instance %s for current system", instanceDigest) unparsedInstance := image.UnparsedInstance(rawSource, &instanceDigest) - - single, err := c.copySingleImage(ctx, unparsedInstance, nil, false) + single, err := c.copySingleImage(ctx, unparsedInstance, nil, copySingleImageOptions{requireCompressionFormatMatch: false}) if err != nil { return nil, fmt.Errorf("copying system image from manifest list: %w", err) } diff --git a/vendor/github.com/containers/image/v5/copy/multiple.go b/vendor/github.com/containers/image/v5/copy/multiple.go index 521383cda..751bb848f 100644 --- a/vendor/github.com/containers/image/v5/copy/multiple.go +++ b/vendor/github.com/containers/image/v5/copy/multiple.go @@ -5,15 +5,19 @@ import ( "context" "errors" "fmt" + "sort" "strings" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/internal/image" internalManifest "github.com/containers/image/v5/internal/manifest" + "github.com/containers/image/v5/internal/set" "github.com/containers/image/v5/manifest" + "github.com/containers/image/v5/pkg/compression" digest "github.com/opencontainers/go-digest" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" + "golang.org/x/exp/maps" "golang.org/x/exp/slices" ) @@ -27,23 +31,118 @@ const ( type instanceCopy struct { op instanceCopyKind sourceDigest digest.Digest + + // Fields which can be used by callers when operation + // is `instanceCopyClone` + cloneCompressionVariant OptionCompressionVariant + clonePlatform *imgspecv1.Platform + cloneAnnotations map[string]string +} + +// internal type only to make imgspecv1.Platform comparable +type platformComparable struct { + architecture string + os string + osVersion string + osFeatures string + variant string +} + +// Converts imgspecv1.Platform to a comparable format. +func platformV1ToPlatformComparable(platform *imgspecv1.Platform) platformComparable { + if platform == nil { + return platformComparable{} + } + osFeatures := slices.Clone(platform.OSFeatures) + sort.Strings(osFeatures) + return platformComparable{architecture: platform.Architecture, + os: platform.OS, + // This is strictly speaking ambiguous, fields of OSFeatures can contain a ','. Probably good enough for now. + osFeatures: strings.Join(osFeatures, ","), + osVersion: platform.OSVersion, + variant: platform.Variant, + } +} + +// platformCompressionMap prepares a mapping of platformComparable -> CompressionAlgorithmNames for given digests +func platformCompressionMap(list internalManifest.List, instanceDigests []digest.Digest) (map[platformComparable]*set.Set[string], error) { + res := make(map[platformComparable]*set.Set[string]) + for _, instanceDigest := range instanceDigests { + instanceDetails, err := list.Instance(instanceDigest) + if err != nil { + return nil, fmt.Errorf("getting details for instance %s: %w", instanceDigest, err) + } + platform := platformV1ToPlatformComparable(instanceDetails.ReadOnly.Platform) + platformSet, ok := res[platform] + if !ok { + platformSet = set.New[string]() + res[platform] = platformSet + } + platformSet.AddSlice(instanceDetails.ReadOnly.CompressionAlgorithmNames) + } + return res, nil +} + +func validateCompressionVariantExists(input []OptionCompressionVariant) error { + for _, option := range input { + _, err := compression.AlgorithmByName(option.Algorithm.Name()) + if err != nil { + return fmt.Errorf("invalid algorithm %q in option.EnsureCompressionVariantsExist: %w", option.Algorithm.Name(), err) + } + } + return nil } // prepareInstanceCopies prepares a list of instances which needs to copied to the manifest list. -func prepareInstanceCopies(instanceDigests []digest.Digest, options *Options) []instanceCopy { +func prepareInstanceCopies(list internalManifest.List, instanceDigests []digest.Digest, options *Options) ([]instanceCopy, error) { res := []instanceCopy{} + if options.ImageListSelection == CopySpecificImages && len(options.EnsureCompressionVariantsExist) > 0 { + // List can already contain compressed instance for a compression selected in `EnsureCompressionVariantsExist` + // It’s unclear what it means when `CopySpecificImages` includes an instance in options.Instances, + // EnsureCompressionVariantsExist asks for an instance with some compression, + // an instance with that compression already exists, but is not included in options.Instances. + // We might define the semantics and implement this in the future. + return res, fmt.Errorf("EnsureCompressionVariantsExist is not implemented for CopySpecificImages") + } + err := validateCompressionVariantExists(options.EnsureCompressionVariantsExist) + if err != nil { + return res, err + } + compressionsByPlatform, err := platformCompressionMap(list, instanceDigests) + if err != nil { + return nil, err + } for i, instanceDigest := range instanceDigests { if options.ImageListSelection == CopySpecificImages && !slices.Contains(options.Instances, instanceDigest) { logrus.Debugf("Skipping instance %s (%d/%d)", instanceDigest, i+1, len(instanceDigests)) continue } + instanceDetails, err := list.Instance(instanceDigest) + if err != nil { + return res, fmt.Errorf("getting details for instance %s: %w", instanceDigest, err) + } + platform := platformV1ToPlatformComparable(instanceDetails.ReadOnly.Platform) + compressionList := compressionsByPlatform[platform] + for _, compressionVariant := range options.EnsureCompressionVariantsExist { + if !compressionList.Contains(compressionVariant.Algorithm.Name()) { + res = append(res, instanceCopy{ + op: instanceCopyClone, + sourceDigest: instanceDigest, + cloneCompressionVariant: compressionVariant, + clonePlatform: instanceDetails.ReadOnly.Platform, + cloneAnnotations: maps.Clone(instanceDetails.ReadOnly.Annotations), + }) + // add current compression to the list so that we don’t create duplicate clones + compressionList.Add(compressionVariant.Algorithm.Name()) + } + } res = append(res, instanceCopy{ op: instanceCopyCopy, sourceDigest: instanceDigest, }) } - return res + return res, nil } // copyMultipleImages copies some or all of an image list's instances, using @@ -118,8 +217,11 @@ func (c *copier) copyMultipleImages(ctx context.Context) (copiedManifest []byte, // Copy each image, or just the ones we want to copy, in turn. instanceDigests := updatedList.Instances() instanceEdits := []internalManifest.ListEdit{} - instanceCopyList := prepareInstanceCopies(instanceDigests, c.options) - c.Printf("Copying %d of %d images in list\n", len(instanceCopyList), len(instanceDigests)) + instanceCopyList, err := prepareInstanceCopies(updatedList, instanceDigests, c.options) + if err != nil { + return nil, fmt.Errorf("preparing instances for copy: %w", err) + } + c.Printf("Copying %d images generated from %d images in list\n", len(instanceCopyList), len(instanceDigests)) for i, instance := range instanceCopyList { // Update instances to be edited by their `ListOperation` and // populate necessary fields. @@ -128,7 +230,7 @@ func (c *copier) copyMultipleImages(ctx context.Context) (copiedManifest []byte, logrus.Debugf("Copying instance %s (%d/%d)", instance.sourceDigest, i+1, len(instanceCopyList)) c.Printf("Copying image %s (%d/%d)\n", instance.sourceDigest, i+1, len(instanceCopyList)) unparsedInstance := image.UnparsedInstance(c.rawSource, &instanceCopyList[i].sourceDigest) - updated, err := c.copySingleImage(ctx, unparsedInstance, &instanceCopyList[i].sourceDigest, false) + updated, err := c.copySingleImage(ctx, unparsedInstance, &instanceCopyList[i].sourceDigest, copySingleImageOptions{requireCompressionFormatMatch: false}) if err != nil { return nil, fmt.Errorf("copying image %d/%d from manifest list: %w", i+1, len(instanceCopyList), err) } @@ -140,6 +242,27 @@ func (c *copier) copyMultipleImages(ctx context.Context) (copiedManifest []byte, UpdateSize: int64(len(updated.manifest)), UpdateCompressionAlgorithms: updated.compressionAlgorithms, UpdateMediaType: updated.manifestMIMEType}) + case instanceCopyClone: + logrus.Debugf("Replicating instance %s (%d/%d)", instance.sourceDigest, i+1, len(instanceCopyList)) + c.Printf("Replicating image %s (%d/%d)\n", instance.sourceDigest, i+1, len(instanceCopyList)) + unparsedInstance := image.UnparsedInstance(c.rawSource, &instanceCopyList[i].sourceDigest) + updated, err := c.copySingleImage(ctx, unparsedInstance, &instanceCopyList[i].sourceDigest, copySingleImageOptions{ + requireCompressionFormatMatch: true, + compressionFormat: &instance.cloneCompressionVariant.Algorithm, + compressionLevel: instance.cloneCompressionVariant.Level}) + if err != nil { + return nil, fmt.Errorf("replicating image %d/%d from manifest list: %w", i+1, len(instanceCopyList), err) + } + // Record the result of a possible conversion here. + instanceEdits = append(instanceEdits, internalManifest.ListEdit{ + ListOperation: internalManifest.ListOpAdd, + AddDigest: updated.manifestDigest, + AddSize: int64(len(updated.manifest)), + AddMediaType: updated.manifestMIMEType, + AddPlatform: instance.clonePlatform, + AddAnnotations: instance.cloneAnnotations, + AddCompressionAlgorithms: updated.compressionAlgorithms, + }) default: return nil, fmt.Errorf("copying image: invalid copy operation %d", instance.op) } diff --git a/vendor/github.com/containers/image/v5/copy/single.go b/vendor/github.com/containers/image/v5/copy/single.go index f0c16beae..5297f019f 100644 --- a/vendor/github.com/containers/image/v5/copy/single.go +++ b/vendor/github.com/containers/image/v5/copy/single.go @@ -40,6 +40,12 @@ type imageCopier struct { requireCompressionFormatMatch bool } +type copySingleImageOptions struct { + requireCompressionFormatMatch bool + compressionFormat *compressiontypes.Algorithm // Compression algorithm to use, if the user explicitly requested one, or nil. + compressionLevel *int +} + // copySingleImageResult carries data produced by copySingleImage type copySingleImageResult struct { manifest []byte @@ -50,7 +56,7 @@ type copySingleImageResult struct { // copySingleImage copies a single (non-manifest-list) image unparsedImage, using c.policyContext to validate // source image admissibility. -func (c *copier) copySingleImage(ctx context.Context, unparsedImage *image.UnparsedImage, targetInstance *digest.Digest, requireCompressionFormatMatch bool) (copySingleImageResult, error) { +func (c *copier) copySingleImage(ctx context.Context, unparsedImage *image.UnparsedImage, targetInstance *digest.Digest, opts copySingleImageOptions) (copySingleImageResult, error) { // The caller is handling manifest lists; this could happen only if a manifest list contains a manifest list. // Make sure we fail cleanly in such cases. multiImage, err := isMultiImage(ctx, unparsedImage) @@ -131,9 +137,12 @@ func (c *copier) copySingleImage(ctx context.Context, unparsedImage *image.Unpar src: src, // diffIDsAreNeeded is computed later cannotModifyManifestReason: cannotModifyManifestReason, - requireCompressionFormatMatch: requireCompressionFormatMatch, + requireCompressionFormatMatch: opts.requireCompressionFormatMatch, } - if c.options.DestinationCtx != nil { + if opts.compressionFormat != nil { + ic.compressionFormat = opts.compressionFormat + ic.compressionLevel = opts.compressionLevel + } else if c.options.DestinationCtx != nil { // Note that compressionFormat and compressionLevel can be nil. ic.compressionFormat = c.options.DestinationCtx.CompressionFormat ic.compressionLevel = c.options.DestinationCtx.CompressionLevel @@ -180,7 +189,7 @@ func (c *copier) copySingleImage(ctx context.Context, unparsedImage *image.Unpar shouldUpdateSigs := len(sigs) > 0 || len(c.signers) != 0 // TODO: Consider allowing signatures updates only and skipping the image's layers/manifest copy if possible noPendingManifestUpdates := ic.noPendingManifestUpdates() - logrus.Debugf("Checking if we can skip copying: has signatures=%t, OCI encryption=%t, no manifest updates=%t, compression match required for resuing blobs=%t", shouldUpdateSigs, destRequiresOciEncryption, noPendingManifestUpdates, requireCompressionFormatMatch) + logrus.Debugf("Checking if we can skip copying: has signatures=%t, OCI encryption=%t, no manifest updates=%t, compression match required for resuing blobs=%t", shouldUpdateSigs, destRequiresOciEncryption, noPendingManifestUpdates, opts.requireCompressionFormatMatch) if !shouldUpdateSigs && !destRequiresOciEncryption && noPendingManifestUpdates && !ic.requireCompressionFormatMatch { matchedResult, err := ic.compareImageDestinationManifestEqual(ctx, targetInstance) if err != nil { diff --git a/vendor/github.com/containers/image/v5/docker/policyconfiguration/naming.go b/vendor/github.com/containers/image/v5/docker/policyconfiguration/naming.go index 5d42c3870..e1f1f1f2b 100644 --- a/vendor/github.com/containers/image/v5/docker/policyconfiguration/naming.go +++ b/vendor/github.com/containers/image/v5/docker/policyconfiguration/naming.go @@ -40,7 +40,7 @@ func DockerReferenceNamespaces(ref reference.Named) []string { // then in its parent "docker.io/library"; in none of "busybox", // un-namespaced "library" nor in "" supposedly implicitly representing "library/". // - // ref.FullName() == ref.Hostname() + "/" + ref.RemoteName(), so the last + // ref.Name() == ref.Domain() + "/" + ref.Path(), so the last // iteration matches the host name (for any namespace). res := []string{} name := ref.Name() diff --git a/vendor/github.com/containers/image/v5/internal/set/set.go b/vendor/github.com/containers/image/v5/internal/set/set.go index 3e777fe12..acf30343e 100644 --- a/vendor/github.com/containers/image/v5/internal/set/set.go +++ b/vendor/github.com/containers/image/v5/internal/set/set.go @@ -28,6 +28,12 @@ func (s *Set[E]) Add(v E) { s.m[v] = struct{}{} // Possibly writing the same struct{}{} presence marker again. } +func (s *Set[E]) AddSlice(slice []E) { + for _, v := range slice { + s.Add(v) + } +} + func (s *Set[E]) Delete(v E) { delete(s.m, v) } diff --git a/vendor/github.com/containers/image/v5/transports/alltransports/alltransports.go b/vendor/github.com/containers/image/v5/transports/alltransports/alltransports.go index 1d9c2dc35..a8f1c13ad 100644 --- a/vendor/github.com/containers/image/v5/transports/alltransports/alltransports.go +++ b/vendor/github.com/containers/image/v5/transports/alltransports/alltransports.go @@ -4,8 +4,11 @@ import ( "fmt" "strings" - // register all known transports - // NOTE: Make sure docs/containers-policy.json.5.md is updated when adding or updating + "github.com/containers/image/v5/transports" + "github.com/containers/image/v5/types" + + // Register all known transports. + // NOTE: Make sure docs/containers-transports.5.md and docs/containers-policy.json.5.md are updated when adding or updating // a transport. _ "github.com/containers/image/v5/directory" _ "github.com/containers/image/v5/docker" @@ -15,11 +18,9 @@ import ( _ "github.com/containers/image/v5/openshift" _ "github.com/containers/image/v5/sif" _ "github.com/containers/image/v5/tarball" - + // The docker-daemon transport is registeredy by docker_daemon*.go // The ostree transport is registered by ostree*.go // The storage transport is registered by storage*.go - "github.com/containers/image/v5/transports" - "github.com/containers/image/v5/types" ) // ParseImageName converts a URL-like image name to a types.ImageReference. diff --git a/vendor/github.com/vbatts/tar-split/archive/tar/reader.go b/vendor/github.com/vbatts/tar-split/archive/tar/reader.go index fcf321553..af006fc92 100644 --- a/vendor/github.com/vbatts/tar-split/archive/tar/reader.go +++ b/vendor/github.com/vbatts/tar-split/archive/tar/reader.go @@ -7,7 +7,6 @@ package tar import ( "bytes" "io" - "io/ioutil" "strconv" "strings" "time" @@ -140,7 +139,7 @@ func (tr *Reader) next() (*Header, error) { continue // This is a meta header affecting the next header case TypeGNULongName, TypeGNULongLink: format.mayOnlyBe(FormatGNU) - realname, err := ioutil.ReadAll(tr) + realname, err := io.ReadAll(tr) if err != nil { return nil, err } @@ -334,7 +333,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) { // parsePAX parses PAX headers. // If an extended header (type 'x') is invalid, ErrHeader is returned func parsePAX(r io.Reader) (map[string]string, error) { - buf, err := ioutil.ReadAll(r) + buf, err := io.ReadAll(r) if err != nil { return nil, err } @@ -916,7 +915,7 @@ func discard(tr *Reader, n int64) error { } } - copySkipped, err = io.CopyN(ioutil.Discard, r, n-seekSkipped) + copySkipped, err = io.CopyN(io.Discard, r, n-seekSkipped) out: if err == io.EOF && seekSkipped+copySkipped < n { err = io.ErrUnexpectedEOF diff --git a/vendor/github.com/vbatts/tar-split/tar/asm/disassemble.go b/vendor/github.com/vbatts/tar-split/tar/asm/disassemble.go index 009b3f5d8..80c2522af 100644 --- a/vendor/github.com/vbatts/tar-split/tar/asm/disassemble.go +++ b/vendor/github.com/vbatts/tar-split/tar/asm/disassemble.go @@ -135,13 +135,15 @@ func NewInputTarStream(r io.Reader, p storage.Packer, fp storage.FilePutter) (io } isEOF = true } - _, err = p.AddEntry(storage.Entry{ - Type: storage.SegmentType, - Payload: paddingChunk[:n], - }) - if err != nil { - pW.CloseWithError(err) - return + if n != 0 { + _, err = p.AddEntry(storage.Entry{ + Type: storage.SegmentType, + Payload: paddingChunk[:n], + }) + if err != nil { + pW.CloseWithError(err) + return + } } if isEOF { break diff --git a/vendor/github.com/vbatts/tar-split/tar/storage/packer.go b/vendor/github.com/vbatts/tar-split/tar/storage/packer.go index aba694818..4ba62d9b7 100644 --- a/vendor/github.com/vbatts/tar-split/tar/storage/packer.go +++ b/vendor/github.com/vbatts/tar-split/tar/storage/packer.go @@ -24,13 +24,6 @@ type Unpacker interface { Next() (*Entry, error) } -/* TODO(vbatts) figure out a good model for this -type PackUnpacker interface { - Packer - Unpacker -} -*/ - type jsonUnpacker struct { seen seenNames dec *json.Decoder @@ -115,13 +108,3 @@ func NewJSONPacker(w io.Writer) Packer { seen: seenNames{}, } } - -/* -TODO(vbatts) perhaps have a more compact packer/unpacker, maybe using msgapck -(https://github.com/ugorji/go) - - -Even though, since our jsonUnpacker and jsonPacker just take -io.Reader/io.Writer, then we can get away with passing them a -gzip.Reader/gzip.Writer -*/ diff --git a/vendor/modules.txt b/vendor/modules.txt index 9f5f67cb8..4d9dc2d0b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -86,7 +86,7 @@ github.com/containernetworking/cni/pkg/version # github.com/containernetworking/plugins v1.3.0 ## explicit; go 1.20 github.com/containernetworking/plugins/pkg/ns -# github.com/containers/image/v5 v5.26.1-0.20230721030518-80390f7f30d1 +# github.com/containers/image/v5 v5.26.1-0.20230726142307-8c387a14f4ac ## explicit; go 1.18 github.com/containers/image/v5/copy github.com/containers/image/v5/directory @@ -582,8 +582,8 @@ github.com/ulikunitz/xz github.com/ulikunitz/xz/internal/hash github.com/ulikunitz/xz/internal/xlog github.com/ulikunitz/xz/lzma -# github.com/vbatts/tar-split v0.11.3 -## explicit; go 1.15 +# github.com/vbatts/tar-split v0.11.5 +## explicit; go 1.17 github.com/vbatts/tar-split/archive/tar github.com/vbatts/tar-split/tar/asm github.com/vbatts/tar-split/tar/storage