Skip to content

Commit

Permalink
feat: upgrade to distribution-spec v1.1.0 (#720)
Browse files Browse the repository at this point in the history
Resolves #709

---------

Signed-off-by: Xiaoxuan Wang <[email protected]>
  • Loading branch information
wangxiaoxuan273 authored Mar 8, 2024
1 parent be59736 commit 0285961
Show file tree
Hide file tree
Showing 16 changed files with 78 additions and 70 deletions.
6 changes: 3 additions & 3 deletions content/oci/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ limitations under the License.
*/

// Package oci provides access to an OCI content store.
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0-rc6/image-layout.md
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0/image-layout.md
package oci

import (
Expand Down Expand Up @@ -43,7 +43,7 @@ import (

// Store implements `oras.Target`, and represents a content store
// based on file system with the OCI-Image layout.
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0-rc6/image-layout.md
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0/image-layout.md
type Store struct {
// AutoSaveIndex controls if the OCI store will automatically save the index
// file when needed.
Expand Down Expand Up @@ -221,7 +221,7 @@ func (s *Store) delete(ctx context.Context, target ocispec.Descriptor) ([]ocispe

// Tag tags a descriptor with a reference string.
// reference should be a valid tag (e.g. "latest").
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0-rc6/image-layout.md#indexjson-file
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0/image-layout.md#indexjson-file
func (s *Store) Tag(ctx context.Context, desc ocispec.Descriptor, reference string) error {
s.sync.RLock()
defer s.sync.RUnlock()
Expand Down
2 changes: 1 addition & 1 deletion content/oci/readonlyoci.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import (

// ReadOnlyStore implements `oras.ReadonlyTarget`, and represents a read-only
// content store based on file system with the OCI-Image layout.
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0-rc4/image-layout.md
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0/image-layout.md
type ReadOnlyStore struct {
fsys fs.FS
storage content.ReadOnlyStorage
Expand Down
2 changes: 1 addition & 1 deletion content/oci/readonlystorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (

// ReadOnlyStorage is a read-only CAS based on file system with the OCI-Image
// layout.
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0-rc4/image-layout.md
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0/image-layout.md
type ReadOnlyStorage struct {
fsys fs.FS
}
Expand Down
2 changes: 1 addition & 1 deletion content/oci/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ var bufPool = sync.Pool{
}

// Storage is a CAS based on file system with the OCI-Image layout.
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0-rc4/image-layout.md
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0/image-layout.md
type Storage struct {
*ReadOnlyStorage
// root is the root directory of the OCI layout.
Expand Down
8 changes: 4 additions & 4 deletions example_pack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import (
"oras.land/oras-go/v2/content/memory"
)

// ExampleImageV11RC4 demonstrates packing an OCI Image Manifest as defined in
// image-spec v1.1.0-rc4.
func ExamplePackManifest_imageV11RC4() {
// ExampleImageV11 demonstrates packing an OCI Image Manifest as defined in
// image-spec v1.1.0.
func ExamplePackManifest_imageV11() {
// 0. Create a storage
store := memory.New()

Expand All @@ -43,7 +43,7 @@ func ExamplePackManifest_imageV11RC4() {

// 2. Pack a manifest
artifactType := "application/vnd.example+type"
manifestDesc, err := oras.PackManifest(ctx, store, oras.PackManifestVersion1_1_RC4, artifactType, opts)
manifestDesc, err := oras.PackManifest(ctx, store, oras.PackManifestVersion1_1, artifactType, opts)
if err != nil {
panic(err)
}
Expand Down
2 changes: 1 addition & 1 deletion example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func Example_pushFilesToRemoteRepository() {
opts := oras.PackManifestOptions{
Layers: fileDescriptors,
}
manifestDescriptor, err := oras.PackManifest(ctx, fs, oras.PackManifestVersion1_1_RC4, artifactType, opts)
manifestDescriptor, err := oras.PackManifest(ctx, fs, oras.PackManifestVersion1_1, artifactType, opts)
if err != nil {
panic(err)
}
Expand Down
28 changes: 18 additions & 10 deletions pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ var (
ErrInvalidDateTimeFormat = errors.New("invalid date and time format")

// ErrMissingArtifactType is returned by [PackManifest] when
// packManifestVersion is PackManifestVersion1_1_RC4 and artifactType is
// packManifestVersion is PackManifestVersion1_1 and artifactType is
// empty and the config media type is set to
// "application/vnd.oci.empty.v1+json".
ErrMissingArtifactType = errors.New("missing artifact type")
Expand All @@ -71,7 +71,15 @@ const (
// PackManifestVersion1_1_RC4 represents the OCI Image Manifest defined
// in image-spec v1.1.0-rc4.
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0-rc4/manifest.md
PackManifestVersion1_1_RC4 PackManifestVersion = 2
//
// Deprecated: This constant is deprecated and not recommended for future use.
// Use [PackManifestVersion1_1] instead.
PackManifestVersion1_1_RC4 PackManifestVersion = PackManifestVersion1_1

// PackManifestVersion1_1 represents the OCI Image Manifest defined in
// image-spec v1.1.0.
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0/manifest.md
PackManifestVersion1_1 PackManifestVersion = 2
)

// PackManifestOptions contains optional parameters for [PackManifest].
Expand All @@ -98,16 +106,16 @@ type PackManifestOptions struct {

// mediaTypeRegexp checks the format of media types.
// References:
// - https://github.com/opencontainers/image-spec/blob/v1.1.0-rc4/schema/defs-descriptor.json#L7
// - https://github.com/opencontainers/image-spec/blob/v1.1.0/schema/defs-descriptor.json#L7
// - https://datatracker.ietf.org/doc/html/rfc6838#section-4.2
var mediaTypeRegexp = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9!#$&-^_.+]{0,126}/[A-Za-z0-9][A-Za-z0-9!#$&-^_.+]{0,126}$`)

// PackManifest generates an OCI Image Manifest based on the given parameters
// and pushes the packed manifest to a content storage using pusher. The version
// of the manifest to be packed is determined by packManifestVersion
// (Recommended value: PackManifestVersion1_1_RC4).
// (Recommended value: PackManifestVersion1_1).
//
// - If packManifestVersion is [PackManifestVersion1_1_RC4]:
// - If packManifestVersion is [PackManifestVersion1_1]:
// artifactType MUST NOT be empty unless opts.ConfigDescriptor is specified.
// - If packManifestVersion is [PackManifestVersion1_0]:
// if opts.ConfigDescriptor is nil, artifactType will be used as the
Expand All @@ -122,8 +130,8 @@ func PackManifest(ctx context.Context, pusher content.Pusher, packManifestVersio
switch packManifestVersion {
case PackManifestVersion1_0:
return packManifestV1_0(ctx, pusher, artifactType, opts)
case PackManifestVersion1_1_RC4:
return packManifestV1_1_RC4(ctx, pusher, artifactType, opts)
case PackManifestVersion1_1:
return packManifestV1_1(ctx, pusher, artifactType, opts)
default:
return ocispec.Descriptor{}, fmt.Errorf("PackManifestVersion(%v): %w", packManifestVersion, errdef.ErrUnsupported)
}
Expand Down Expand Up @@ -283,9 +291,9 @@ func packManifestV1_1_RC2(ctx context.Context, pusher content.Pusher, configMedi
return pushManifest(ctx, pusher, manifest, manifest.MediaType, manifest.Config.MediaType, manifest.Annotations)
}

// packManifestV1_1_RC4 packs an image manifest defined in image-spec v1.1.0-rc4.
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0-rc4/manifest.md#guidelines-for-artifact-usage
func packManifestV1_1_RC4(ctx context.Context, pusher content.Pusher, artifactType string, opts PackManifestOptions) (ocispec.Descriptor, error) {
// packManifestV1_1 packs an image manifest defined in image-spec v1.1.0.
// Reference: https://github.com/opencontainers/image-spec/blob/v1.1.0/manifest.md#guidelines-for-artifact-usage
func packManifestV1_1(ctx context.Context, pusher content.Pusher, artifactType string, opts PackManifestOptions) (ocispec.Descriptor, error) {
if artifactType == "" && (opts.ConfigDescriptor == nil || opts.ConfigDescriptor.MediaType == ocispec.MediaTypeEmptyJSON) {
// artifactType MUST be set when config.mediaType is set to the empty value
return ocispec.Descriptor{}, ErrMissingArtifactType
Expand Down
28 changes: 14 additions & 14 deletions pack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -801,13 +801,13 @@ func Test_PackManifest_ImageV1_0_InvalidDateTimeFormat(t *testing.T) {
}
}

func Test_PackManifest_ImageV1_1_RC4(t *testing.T) {
func Test_PackManifest_ImageV1_1(t *testing.T) {
s := memory.New()

// test PackManifest
ctx := context.Background()
artifactType := "application/vnd.test"
manifestDesc, err := PackManifest(ctx, s, PackManifestVersion1_1_RC4, artifactType, PackManifestOptions{})
manifestDesc, err := PackManifest(ctx, s, PackManifestVersion1_1, artifactType, PackManifestOptions{})
if err != nil {
t.Fatal("Oras.PackManifest() error =", err)
}
Expand All @@ -831,7 +831,7 @@ func Test_PackManifest_ImageV1_1_RC4(t *testing.T) {
}
}

func Test_PackManifest_ImageV1_1_RC4_WithOptions(t *testing.T) {
func Test_PackManifest_ImageV1_1_WithOptions(t *testing.T) {
s := memory.New()

// prepare test content
Expand Down Expand Up @@ -863,7 +863,7 @@ func Test_PackManifest_ImageV1_1_RC4_WithOptions(t *testing.T) {
ConfigAnnotations: configAnnotations,
ManifestAnnotations: annotations,
}
manifestDesc, err := PackManifest(ctx, s, PackManifestVersion1_1_RC4, artifactType, opts)
manifestDesc, err := PackManifest(ctx, s, PackManifestVersion1_1, artifactType, opts)
if err != nil {
t.Fatal("Oras.PackManifest() error =", err)
}
Expand Down Expand Up @@ -916,7 +916,7 @@ func Test_PackManifest_ImageV1_1_RC4_WithOptions(t *testing.T) {
ConfigAnnotations: configAnnotations,
ManifestAnnotations: annotations,
}
manifestDesc, err = PackManifest(ctx, s, PackManifestVersion1_1_RC4, "", opts)
manifestDesc, err = PackManifest(ctx, s, PackManifestVersion1_1, "", opts)
if err != nil {
t.Fatal("Oras.PackManifest() error =", err)
}
Expand Down Expand Up @@ -967,7 +967,7 @@ func Test_PackManifest_ImageV1_1_RC4_WithOptions(t *testing.T) {
ConfigAnnotations: configAnnotations,
ManifestAnnotations: annotations,
}
manifestDesc, err = PackManifest(ctx, s, PackManifestVersion1_1_RC4, artifactType, opts)
manifestDesc, err = PackManifest(ctx, s, PackManifestVersion1_1, artifactType, opts)
if err != nil {
t.Fatal("Oras.PackManifest() error =", err)
}
Expand Down Expand Up @@ -1015,12 +1015,12 @@ func Test_PackManifest_ImageV1_1_RC4_WithOptions(t *testing.T) {
}
}

func Test_PackManifest_ImageV1_1_RC4_NoArtifactType(t *testing.T) {
func Test_PackManifest_ImageV1_1_NoArtifactType(t *testing.T) {
s := memory.New()

ctx := context.Background()
// test no artifact type and no config
_, err := PackManifest(ctx, s, PackManifestVersion1_1_RC4, "", PackManifestOptions{})
_, err := PackManifest(ctx, s, PackManifestVersion1_1, "", PackManifestOptions{})
if wantErr := ErrMissingArtifactType; !errors.Is(err, wantErr) {
t.Errorf("Oras.PackManifest() error = %v, wantErr = %v", err, wantErr)
}
Expand All @@ -1031,13 +1031,13 @@ func Test_PackManifest_ImageV1_1_RC4_NoArtifactType(t *testing.T) {
MediaType: ocispec.DescriptorEmptyJSON.MediaType,
},
}
_, err = PackManifest(ctx, s, PackManifestVersion1_1_RC4, "", opts)
_, err = PackManifest(ctx, s, PackManifestVersion1_1, "", opts)
if wantErr := ErrMissingArtifactType; !errors.Is(err, wantErr) {
t.Errorf("Oras.PackManifest() error = %v, wantErr = %v", err, wantErr)
}
}

func Test_PackManifest_ImageV1_1_RC4_InvalidMediaType(t *testing.T) {
func Test_PackManifest_ImageV1_1_InvalidMediaType(t *testing.T) {
s := memory.New()

ctx := context.Background()
Expand All @@ -1048,7 +1048,7 @@ func Test_PackManifest_ImageV1_1_RC4_InvalidMediaType(t *testing.T) {
opts := PackManifestOptions{
ConfigDescriptor: &configDesc,
}
_, err := PackManifest(ctx, s, PackManifestVersion1_1_RC4, artifactType, opts)
_, err := PackManifest(ctx, s, PackManifestVersion1_1, artifactType, opts)
if wantErr := errdef.ErrInvalidMediaType; !errors.Is(err, wantErr) {
t.Errorf("Oras.PackManifest() error = %v, wantErr = %v", err, wantErr)
}
Expand All @@ -1059,13 +1059,13 @@ func Test_PackManifest_ImageV1_1_RC4_InvalidMediaType(t *testing.T) {
opts = PackManifestOptions{
ConfigDescriptor: &configDesc,
}
_, err = PackManifest(ctx, s, PackManifestVersion1_1_RC4, artifactType, opts)
_, err = PackManifest(ctx, s, PackManifestVersion1_1, artifactType, opts)
if wantErr := errdef.ErrInvalidMediaType; !errors.Is(err, wantErr) {
t.Errorf("Oras.PackManifest() error = %v, wantErr = %v", err, wantErr)
}
}

func Test_PackManifest_ImageV1_1_RC4_InvalidDateTimeFormat(t *testing.T) {
func Test_PackManifest_ImageV1_1_InvalidDateTimeFormat(t *testing.T) {
s := memory.New()

ctx := context.Background()
Expand All @@ -1075,7 +1075,7 @@ func Test_PackManifest_ImageV1_1_RC4_InvalidDateTimeFormat(t *testing.T) {
},
}
artifactType := "application/vnd.test"
_, err := PackManifest(ctx, s, PackManifestVersion1_1_RC4, artifactType, opts)
_, err := PackManifest(ctx, s, PackManifestVersion1_1, artifactType, opts)
if wantErr := ErrInvalidDateTimeFormat; !errors.Is(err, wantErr) {
t.Errorf("Oras.PackManifest() error = %v, wantErr = %v", err, wantErr)
}
Expand Down
4 changes: 2 additions & 2 deletions registry/reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ var (
//
// References:
// - https://github.com/distribution/distribution/blob/v2.7.1/reference/regexp.go#L53
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#pulling-manifests
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#pulling-manifests
repositoryRegexp = regexp.MustCompile(`^[a-z0-9]+(?:(?:[._]|__|[-]*)[a-z0-9]+)*(?:/[a-z0-9]+(?:(?:[._]|__|[-]*)[a-z0-9]+)*)*$`)

// tagRegexp checks the tag name.
// The docker and OCI spec have the same regular expression.
//
// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#pulling-manifests
// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#pulling-manifests
tagRegexp = regexp.MustCompile(`^[\w][\w.-]{0,127}$`)
)

Expand Down
6 changes: 3 additions & 3 deletions registry/remote/errcode/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
)

// References:
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#error-codes
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#error-codes
// - https://docs.docker.com/registry/spec/api/#errors-2
const (
ErrorCodeBlobUnknown = "BLOB_UNKNOWN"
Expand All @@ -45,7 +45,7 @@ const (
// Error represents a response inner error returned by the remote
// registry.
// References:
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#error-codes
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#error-codes
// - https://docs.docker.com/registry/spec/api/#errors-2
type Error struct {
Code string `json:"code"`
Expand Down Expand Up @@ -73,7 +73,7 @@ func (e Error) Error() string {
// Errors represents a list of response inner errors returned by the remote
// server.
// References:
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#error-codes
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#error-codes
// - https://docs.docker.com/registry/spec/api/#errors-2
type Errors []Error

Expand Down
2 changes: 1 addition & 1 deletion registry/remote/referrers.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func (e *ReferrersError) IsReferrersIndexDelete() bool {

// buildReferrersTag builds the referrers tag for the given manifest descriptor.
// Format: <algorithm>-<digest>
// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#unavailable-referrers-api
// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#unavailable-referrers-api
func buildReferrersTag(desc ocispec.Descriptor) string {
alg := desc.Digest.Algorithm().String()
encoded := desc.Digest.Encoded()
Expand Down
2 changes: 1 addition & 1 deletion registry/remote/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (r *Registry) do(req *http.Request) (*http.Response, error) {
//
// References:
// - https://docs.docker.com/registry/spec/api/#base
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc4/spec.md#api
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#api
func (r *Registry) Ping(ctx context.Context) error {
url := buildRegistryBaseURL(r.PlainHTTP, r.Reference)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
Expand Down
Loading

0 comments on commit 0285961

Please sign in to comment.