manifest.go 4.2 KB

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