145 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
package schema2
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
 | 
						|
	"github.com/distribution/distribution/v3"
 | 
						|
	"github.com/distribution/distribution/v3/manifest"
 | 
						|
	"github.com/opencontainers/go-digest"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	// MediaTypeManifest specifies the mediaType for the current version.
 | 
						|
	MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json"
 | 
						|
 | 
						|
	// MediaTypeImageConfig specifies the mediaType for the image configuration.
 | 
						|
	MediaTypeImageConfig = "application/vnd.docker.container.image.v1+json"
 | 
						|
 | 
						|
	// MediaTypePluginConfig specifies the mediaType for plugin configuration.
 | 
						|
	MediaTypePluginConfig = "application/vnd.docker.plugin.v1+json"
 | 
						|
 | 
						|
	// MediaTypeLayer is the mediaType used for layers referenced by the
 | 
						|
	// manifest.
 | 
						|
	MediaTypeLayer = "application/vnd.docker.image.rootfs.diff.tar.gzip"
 | 
						|
 | 
						|
	// MediaTypeForeignLayer is the mediaType used for layers that must be
 | 
						|
	// downloaded from foreign URLs.
 | 
						|
	MediaTypeForeignLayer = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip"
 | 
						|
 | 
						|
	// MediaTypeUncompressedLayer is the mediaType used for layers which
 | 
						|
	// are not compressed.
 | 
						|
	MediaTypeUncompressedLayer = "application/vnd.docker.image.rootfs.diff.tar"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	// SchemaVersion provides a pre-initialized version structure for this
 | 
						|
	// packages version of the manifest.
 | 
						|
	SchemaVersion = manifest.Versioned{
 | 
						|
		SchemaVersion: 2,
 | 
						|
		MediaType:     MediaTypeManifest,
 | 
						|
	}
 | 
						|
)
 | 
						|
 | 
						|
func init() {
 | 
						|
	schema2Func := func(b []byte) (distribution.Manifest, distribution.Descriptor, error) {
 | 
						|
		m := new(DeserializedManifest)
 | 
						|
		err := m.UnmarshalJSON(b)
 | 
						|
		if err != nil {
 | 
						|
			return nil, distribution.Descriptor{}, err
 | 
						|
		}
 | 
						|
 | 
						|
		dgst := digest.FromBytes(b)
 | 
						|
		return m, distribution.Descriptor{Digest: dgst, Size: int64(len(b)), MediaType: MediaTypeManifest}, err
 | 
						|
	}
 | 
						|
	err := distribution.RegisterManifestSchema(MediaTypeManifest, schema2Func)
 | 
						|
	if err != nil {
 | 
						|
		panic(fmt.Sprintf("Unable to register manifest: %s", err))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Manifest defines a schema2 manifest.
 | 
						|
type Manifest struct {
 | 
						|
	manifest.Versioned
 | 
						|
 | 
						|
	// Config references the image configuration as a blob.
 | 
						|
	Config distribution.Descriptor `json:"config"`
 | 
						|
 | 
						|
	// Layers lists descriptors for the layers referenced by the
 | 
						|
	// configuration.
 | 
						|
	Layers []distribution.Descriptor `json:"layers"`
 | 
						|
}
 | 
						|
 | 
						|
// References returns the descriptors of this manifests references.
 | 
						|
func (m Manifest) References() []distribution.Descriptor {
 | 
						|
	references := make([]distribution.Descriptor, 0, 1+len(m.Layers))
 | 
						|
	references = append(references, m.Config)
 | 
						|
	references = append(references, m.Layers...)
 | 
						|
	return references
 | 
						|
}
 | 
						|
 | 
						|
// Target returns the target of this manifest.
 | 
						|
func (m Manifest) Target() distribution.Descriptor {
 | 
						|
	return m.Config
 | 
						|
}
 | 
						|
 | 
						|
// DeserializedManifest wraps Manifest with a copy of the original JSON.
 | 
						|
// It satisfies the distribution.Manifest interface.
 | 
						|
type DeserializedManifest struct {
 | 
						|
	Manifest
 | 
						|
 | 
						|
	// canonical is the canonical byte representation of the Manifest.
 | 
						|
	canonical []byte
 | 
						|
}
 | 
						|
 | 
						|
// FromStruct takes a Manifest structure, marshals it to JSON, and returns a
 | 
						|
// DeserializedManifest which contains the manifest and its JSON representation.
 | 
						|
func FromStruct(m Manifest) (*DeserializedManifest, error) {
 | 
						|
	var deserialized DeserializedManifest
 | 
						|
	deserialized.Manifest = m
 | 
						|
 | 
						|
	var err error
 | 
						|
	deserialized.canonical, err = json.MarshalIndent(&m, "", "   ")
 | 
						|
	return &deserialized, err
 | 
						|
}
 | 
						|
 | 
						|
// UnmarshalJSON populates a new Manifest struct from JSON data.
 | 
						|
func (m *DeserializedManifest) UnmarshalJSON(b []byte) error {
 | 
						|
	m.canonical = make([]byte, len(b))
 | 
						|
	// store manifest in canonical
 | 
						|
	copy(m.canonical, b)
 | 
						|
 | 
						|
	// Unmarshal canonical JSON into Manifest object
 | 
						|
	var manifest Manifest
 | 
						|
	if err := json.Unmarshal(m.canonical, &manifest); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if manifest.MediaType != MediaTypeManifest {
 | 
						|
		return fmt.Errorf("mediaType in manifest should be '%s' not '%s'",
 | 
						|
			MediaTypeManifest, manifest.MediaType)
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	m.Manifest = manifest
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// MarshalJSON returns the contents of canonical. If canonical is empty,
 | 
						|
// marshals the inner contents.
 | 
						|
func (m *DeserializedManifest) MarshalJSON() ([]byte, error) {
 | 
						|
	if len(m.canonical) > 0 {
 | 
						|
		return m.canonical, nil
 | 
						|
	}
 | 
						|
 | 
						|
	return nil, errors.New("JSON representation not initialized in DeserializedManifest")
 | 
						|
}
 | 
						|
 | 
						|
// Payload returns the raw content of the manifest. The contents can be used to
 | 
						|
// calculate the content identifier.
 | 
						|
func (m DeserializedManifest) Payload() (string, []byte, error) {
 | 
						|
	return m.MediaType, m.canonical, nil
 | 
						|
}
 |