f1c8c41408
Commitcb6f002350
implemented a generic Manifest interface to represent manifests in the registry and remove references to schema specific manifests. As part of this refactor, the Describable interface was introduced, which allowed for a single ManifestBuilder interface to handle both schema1 and schema2 manifests. Implementations of Describable are generally objects which can be described, not simply descriptors, but for convenience, this interface was also implemented on Descriptor in2ff77c00ba
. This interface served its purpose, but no longer needed for most cases; schema2 (and OCI) descriptors do not need this method, making it only needed for `schema1.Reference`, which is now deprecated. Requiring this interface to be implemented limits interoperability between distribution's Descriptor and the OCI Descriptor types, which are identical in every other way, except for the presence of the Describable interface. This patch: - Removes the `Descriptor.Descriptor()` method (no longer implementing the `Describable` interface). - Updates ManifestBuilder interface and implementations to accept either - Updates ManifestBuilder interface and implementations to accept a `Descriptor`. After this patch, the caller is responsible for changing a describable type into a descriptor; builder.AppendReference(describable.Descriptor()) Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
107 lines
3.1 KiB
Go
107 lines
3.1 KiB
Go
package ocischema
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/distribution/distribution/v3"
|
|
"github.com/distribution/distribution/v3/manifest"
|
|
"github.com/opencontainers/go-digest"
|
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
|
)
|
|
|
|
// Builder is a type for constructing manifests.
|
|
type Builder struct {
|
|
// bs is a BlobService used to publish the configuration blob.
|
|
bs distribution.BlobService
|
|
|
|
// configJSON references
|
|
configJSON []byte
|
|
|
|
// layers is a list of layer descriptors that gets built by successive
|
|
// calls to AppendReference.
|
|
layers []distribution.Descriptor
|
|
|
|
// Annotations contains arbitrary metadata relating to the targeted content.
|
|
annotations map[string]string
|
|
|
|
// For testing purposes
|
|
mediaType string
|
|
}
|
|
|
|
// NewManifestBuilder is used to build new manifests for the current schema
|
|
// version. It takes a BlobService so it can publish the configuration blob
|
|
// as part of the Build process, and annotations.
|
|
func NewManifestBuilder(bs distribution.BlobService, configJSON []byte, annotations map[string]string) *Builder {
|
|
mb := &Builder{
|
|
bs: bs,
|
|
configJSON: make([]byte, len(configJSON)),
|
|
annotations: annotations,
|
|
mediaType: v1.MediaTypeImageManifest,
|
|
}
|
|
copy(mb.configJSON, configJSON)
|
|
|
|
return mb
|
|
}
|
|
|
|
// SetMediaType assigns the passed mediatype or error if the mediatype is not a
|
|
// valid media type for oci image manifests currently: "" or "application/vnd.oci.image.manifest.v1+json"
|
|
func (mb *Builder) SetMediaType(mediaType string) error {
|
|
if mediaType != "" && mediaType != v1.MediaTypeImageManifest {
|
|
return errors.New("invalid media type for OCI image manifest")
|
|
}
|
|
|
|
mb.mediaType = mediaType
|
|
return nil
|
|
}
|
|
|
|
// Build produces a final manifest from the given references.
|
|
func (mb *Builder) Build(ctx context.Context) (distribution.Manifest, error) {
|
|
m := Manifest{
|
|
Versioned: manifest.Versioned{
|
|
SchemaVersion: 2,
|
|
MediaType: mb.mediaType,
|
|
},
|
|
Layers: make([]distribution.Descriptor, len(mb.layers)),
|
|
Annotations: mb.annotations,
|
|
}
|
|
copy(m.Layers, mb.layers)
|
|
|
|
configDigest := digest.FromBytes(mb.configJSON)
|
|
|
|
var err error
|
|
m.Config, err = mb.bs.Stat(ctx, configDigest)
|
|
switch err {
|
|
case nil:
|
|
// Override MediaType, since Put always replaces the specified media
|
|
// type with application/octet-stream in the descriptor it returns.
|
|
m.Config.MediaType = v1.MediaTypeImageConfig
|
|
return FromStruct(m)
|
|
case distribution.ErrBlobUnknown:
|
|
// nop
|
|
default:
|
|
return nil, err
|
|
}
|
|
|
|
// Add config to the blob store
|
|
m.Config, err = mb.bs.Put(ctx, v1.MediaTypeImageConfig, mb.configJSON)
|
|
// Override MediaType, since Put always replaces the specified media
|
|
// type with application/octet-stream in the descriptor it returns.
|
|
m.Config.MediaType = v1.MediaTypeImageConfig
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return FromStruct(m)
|
|
}
|
|
|
|
// AppendReference adds a reference to the current ManifestBuilder.
|
|
func (mb *Builder) AppendReference(ref distribution.Descriptor) error {
|
|
mb.layers = append(mb.layers, ref)
|
|
return nil
|
|
}
|
|
|
|
// References returns the current references added to this builder.
|
|
func (mb *Builder) References() []distribution.Descriptor {
|
|
return mb.layers
|
|
}
|