github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/manifest/schema2/manifest.go (about)

     1  package schema2
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/docker/distribution"
     9  	"github.com/docker/distribution/digest"
    10  	"github.com/docker/distribution/manifest"
    11  )
    12  
    13  const (
    14  	// MediaTypeManifest specifies the mediaType for the current version.
    15  	MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json"
    16  
    17  	// MediaTypeConfig specifies the mediaType for the image configuration.
    18  	MediaTypeConfig = "application/vnd.docker.container.image.v1+json"
    19  
    20  	// MediaTypeLayer is the mediaType used for layers referenced by the
    21  	// manifest.
    22  	MediaTypeLayer = "application/vnd.docker.image.rootfs.diff.tar.gzip"
    23  )
    24  
    25  var (
    26  	// SchemaVersion provides a pre-initialized version structure for this
    27  	// packages version of the manifest.
    28  	SchemaVersion = manifest.Versioned{
    29  		SchemaVersion: 2,
    30  		MediaType:     MediaTypeManifest,
    31  	}
    32  )
    33  
    34  func init() {
    35  	schema2Func := func(b []byte) (distribution.Manifest, distribution.Descriptor, error) {
    36  		m := new(DeserializedManifest)
    37  		err := m.UnmarshalJSON(b)
    38  		if err != nil {
    39  			return nil, distribution.Descriptor{}, err
    40  		}
    41  
    42  		dgst := digest.FromBytes(b)
    43  		return m, distribution.Descriptor{Digest: dgst, Size: int64(len(b)), MediaType: MediaTypeManifest}, err
    44  	}
    45  	err := distribution.RegisterManifestSchema(MediaTypeManifest, schema2Func)
    46  	if err != nil {
    47  		panic(fmt.Sprintf("Unable to register manifest: %s", err))
    48  	}
    49  }
    50  
    51  // Manifest defines a schema2 manifest.
    52  type Manifest struct {
    53  	manifest.Versioned
    54  
    55  	// Config references the image configuration as a blob.
    56  	Config distribution.Descriptor `json:"config"`
    57  
    58  	// Layers lists descriptors for the layers referenced by the
    59  	// configuration.
    60  	Layers []distribution.Descriptor `json:"layers"`
    61  }
    62  
    63  // References returnes the descriptors of this manifests references.
    64  func (m Manifest) References() []distribution.Descriptor {
    65  	return m.Layers
    66  
    67  }
    68  
    69  // Target returns the target of this signed manifest.
    70  func (m Manifest) Target() distribution.Descriptor {
    71  	return m.Config
    72  }
    73  
    74  // DeserializedManifest wraps Manifest with a copy of the original JSON.
    75  // It satisfies the distribution.Manifest interface.
    76  type DeserializedManifest struct {
    77  	Manifest
    78  
    79  	// canonical is the canonical byte representation of the Manifest.
    80  	canonical []byte
    81  }
    82  
    83  // FromStruct takes a Manifest structure, marshals it to JSON, and returns a
    84  // DeserializedManifest which contains the manifest and its JSON representation.
    85  func FromStruct(m Manifest) (*DeserializedManifest, error) {
    86  	var deserialized DeserializedManifest
    87  	deserialized.Manifest = m
    88  
    89  	var err error
    90  	deserialized.canonical, err = json.MarshalIndent(&m, "", "   ")
    91  	return &deserialized, err
    92  }
    93  
    94  // UnmarshalJSON populates a new Manifest struct from JSON data.
    95  func (m *DeserializedManifest) UnmarshalJSON(b []byte) error {
    96  	m.canonical = make([]byte, len(b), len(b))
    97  	// store manifest in canonical
    98  	copy(m.canonical, b)
    99  
   100  	// Unmarshal canonical JSON into Manifest object
   101  	var manifest Manifest
   102  	if err := json.Unmarshal(m.canonical, &manifest); err != nil {
   103  		return err
   104  	}
   105  
   106  	m.Manifest = manifest
   107  
   108  	return nil
   109  }
   110  
   111  // MarshalJSON returns the contents of canonical. If canonical is empty,
   112  // marshals the inner contents.
   113  func (m *DeserializedManifest) MarshalJSON() ([]byte, error) {
   114  	if len(m.canonical) > 0 {
   115  		return m.canonical, nil
   116  	}
   117  
   118  	return nil, errors.New("JSON representation not initialized in DeserializedManifest")
   119  }
   120  
   121  // Payload returns the raw content of the manifest. The contents can be used to
   122  // calculate the content identifier.
   123  func (m DeserializedManifest) Payload() (string, []byte, error) {
   124  	return m.MediaType, m.canonical, nil
   125  }