1 package distribution 2 3 import ( 4 "context" 5 "fmt" 6 "mime" 7 8 "github.com/opencontainers/go-digest" 9 ) 10 11 // Manifest represents a registry object specifying a set of 12 // references and an optional target 13 type Manifest interface { 14 // References returns a list of objects which make up this manifest. 15 // A reference is anything which can be represented by a 16 // distribution.Descriptor. These can consist of layers, resources or other 17 // manifests. 18 // 19 // While no particular order is required, implementations should return 20 // them from highest to lowest priority. For example, one might want to 21 // return the base layer before the top layer. 22 References() []Descriptor 23 24 // Payload provides the serialized format of the manifest, in addition to 25 // the media type. 26 Payload() (mediaType string, payload []byte, err error) 27 } 28 29 // ManifestBuilder creates a manifest allowing one to include dependencies. 30 // Instances can be obtained from a version-specific manifest package. Manifest 31 // specific data is passed into the function which creates the builder. 32 type ManifestBuilder interface { 33 // Build creates the manifest from his builder. 34 Build(ctx context.Context) (Manifest, error) 35 36 // References returns a list of objects which have been added to this 37 // builder. The dependencies are returned in the order they were added, 38 // which should be from base to head. 39 References() []Descriptor 40 41 // AppendReference includes the given object in the manifest after any 42 // existing dependencies. If the add fails, such as when adding an 43 // unsupported dependency, an error may be returned. 44 // 45 // The destination of the reference is dependent on the manifest type and 46 // the dependency type. 47 AppendReference(dependency Describable) error 48 } 49 50 // ManifestService describes operations on image manifests. 51 type ManifestService interface { 52 // Exists returns true if the manifest exists. 53 Exists(ctx context.Context, dgst digest.Digest) (bool, error) 54 55 // Get retrieves the manifest specified by the given digest 56 Get(ctx context.Context, dgst digest.Digest, options ...ManifestServiceOption) (Manifest, error) 57 58 // Put creates or updates the given manifest returning the manifest digest 59 Put(ctx context.Context, manifest Manifest, options ...ManifestServiceOption) (digest.Digest, error) 60 61 // Delete removes the manifest specified by the given digest. Deleting 62 // a manifest that doesn't exist will return ErrManifestNotFound 63 Delete(ctx context.Context, dgst digest.Digest) error 64 } 65 66 // ManifestEnumerator enables iterating over manifests 67 type ManifestEnumerator interface { 68 // Enumerate calls ingester for each manifest. 69 Enumerate(ctx context.Context, ingester func(digest.Digest) error) error 70 } 71 72 // Describable is an interface for descriptors 73 type Describable interface { 74 Descriptor() Descriptor 75 } 76 77 // ManifestMediaTypes returns the supported media types for manifests. 78 func ManifestMediaTypes() (mediaTypes []string) { 79 for t := range mappings { 80 if t != "" { 81 mediaTypes = append(mediaTypes, t) 82 } 83 } 84 return 85 } 86 87 // UnmarshalFunc implements manifest unmarshalling a given MediaType 88 type UnmarshalFunc func([]byte) (Manifest, Descriptor, error) 89 90 var mappings = make(map[string]UnmarshalFunc) 91 92 // UnmarshalManifest looks up manifest unmarshal functions based on 93 // MediaType 94 func UnmarshalManifest(ctHeader string, p []byte) (Manifest, Descriptor, error) { 95 // Need to look up by the actual media type, not the raw contents of 96 // the header. Strip semicolons and anything following them. 97 var mediaType string 98 if ctHeader != "" { 99 var err error 100 mediaType, _, err = mime.ParseMediaType(ctHeader) 101 if err != nil { 102 return nil, Descriptor{}, err 103 } 104 } 105 106 unmarshalFunc, ok := mappings[mediaType] 107 if !ok { 108 unmarshalFunc, ok = mappings[""] 109 if !ok { 110 return nil, Descriptor{}, fmt.Errorf("unsupported manifest media type and no default available: %s", mediaType) 111 } 112 } 113 114 return unmarshalFunc(p) 115 } 116 117 // RegisterManifestSchema registers an UnmarshalFunc for a given schema type. This 118 // should be called from specific 119 func RegisterManifestSchema(mediaType string, u UnmarshalFunc) error { 120 if _, ok := mappings[mediaType]; ok { 121 return fmt.Errorf("manifest media type registration would overwrite existing: %s", mediaType) 122 } 123 mappings[mediaType] = u 124 return nil 125 } 126