diff --git a/src/OrasProject.Oras/Constants/OCIMediaTypes .cs b/src/OrasProject.Oras/Constants/OCIMediaTypes .cs
deleted file mode 100644
index 6eccb43..0000000
--- a/src/OrasProject.Oras/Constants/OCIMediaTypes .cs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright The ORAS Authors.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-namespace OrasProject.Oras.Constants
-{
- public static class OCIMediaTypes
- {
- // MediaTypeDescriptor specifies the media type for a content descriptor.
- public const string Descriptor = "application/vnd.oci.descriptor.v1+json";
-
- // MediaTypeLayoutHeader specifies the media type for the oci-layout.
- public const string LayoutHeader = "application/vnd.oci.layout.header.v1+json";
-
- // MediaTypeImageManifest specifies the media type for an image manifest.
- public const string ImageManifest = "application/vnd.oci.image.manifest.v1+json";
-
- // MediaTypeImageIndex specifies the media type for an image index.
- public const string ImageIndex = "application/vnd.oci.image.index.v1+json";
-
- // MediaTypeImageLayer is the media type used for layers referenced by the manifest.
- public const string ImageLayer = "application/vnd.oci.image.layer.v1.tar";
-
- // MediaTypeImageLayerGzip is the media type used for gzipped layers
- // referenced by the manifest.
- public const string ImageLayerGzip = "application/vnd.oci.image.layer.v1.tar+gzip";
-
- // MediaTypeImageLayerZstd is the media type used for zstd compressed
- // layers referenced by the manifest.
- public const string ImageLayerZstd = "application/vnd.oci.image.layer.v1.tar+zstd";
-
- // MediaTypeImageLayerNonDistributable is the media type for layers referenced by
- // the manifest but with distribution restrictions.
- public const string ImageLayerNonDistributable = "application/vnd.oci.image.layer.nondistributable.v1.tar";
-
- // MediaTypeImageLayerNonDistributableGzip is the media type for
- // gzipped layers referenced by the manifest but with distribution
- // restrictions.
- public const string ImageLayerNonDistributableGzip = "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip";
-
- // MediaTypeImageLayerNonDistributableZstd is the media type for zstd
- // compressed layers referenced by the manifest but with distribution
- // restrictions.
- public const string ImageLayerNonDistributableZstd = "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd";
-
- // MediaTypeImageConfig specifies the media type for the image configuration.
- public const string ImageConfig = "application/vnd.oci.image.config.v1+json";
-
- }
-}
diff --git a/src/OrasProject.Oras/Content/Content.cs b/src/OrasProject.Oras/Content/Content.cs
deleted file mode 100644
index 738c1f4..0000000
--- a/src/OrasProject.Oras/Content/Content.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright The ORAS Authors.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OrasProject.Oras.Constants;
-using OrasProject.Oras.Exceptions;
-using OrasProject.Oras.Interfaces;
-using OrasProject.Oras.Models;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Security.Cryptography;
-using System.Text.Json;
-using System.Threading;
-using System.Threading.Tasks;
-using Index = OrasProject.Oras.Models.Index;
-
-namespace OrasProject.Oras.Content
-{
- public static class Content
- {
- ///
- /// Retrieves the successors of a node
- ///
- ///
- ///
- ///
- ///
- public static async Task> SuccessorsAsync(IFetcher fetcher, Descriptor node, CancellationToken cancellationToken)
- {
- switch (node.MediaType)
- {
- case DockerMediaTypes.Manifest:
- case OCIMediaTypes.ImageManifest:
- {
- var content = await FetchAllAsync(fetcher, node, cancellationToken);
- var manifest = JsonSerializer.Deserialize(content);
- var descriptors = new List() { manifest.Config };
- descriptors.AddRange(manifest.Layers);
- return descriptors;
- }
- case DockerMediaTypes.ManifestList:
- case OCIMediaTypes.ImageIndex:
- {
- var content = await FetchAllAsync(fetcher, node, cancellationToken);
- // docker manifest list and oci index are equivalent for successors.
- var index = JsonSerializer.Deserialize(content);
- return index.Manifests;
- }
- }
- return default;
- }
-
- ///
- /// Fetches all the content for a given descriptor.
- /// Currently only sha256 is supported but we would supports others hash algorithms in the future.
- ///
- ///
- ///
- ///
- ///
- public static async Task FetchAllAsync(IFetcher fetcher, Descriptor desc, CancellationToken cancellationToken)
- {
- var stream = await fetcher.FetchAsync(desc, cancellationToken);
- return await ReadAllAsync(stream, desc);
- }
-
- ///
- /// Calculates the digest of the content
- /// Currently only sha256 is supported but we would supports others hash algorithms in the future.
- ///
- ///
- ///
- internal static string CalculateDigest(byte[] content)
- {
- using var sha256 = SHA256.Create();
- var hash = sha256.ComputeHash(content);
- var output = $"{nameof(SHA256)}:{BitConverter.ToString(hash).Replace("-", "")}";
- return output.ToLower();
- }
-
- ///
- /// Reads and verifies the content from a stream
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- internal static async Task ReadAllAsync(Stream stream, Descriptor descriptor)
- {
- if (descriptor.Size < 0)
- {
- throw new InvalidDescriptorSizeException("this descriptor size is less than 0");
- }
- var buffer = new byte[descriptor.Size];
- try
- {
- await stream.ReadAsync(buffer, 0, (int)stream.Length);
- }
- catch (ArgumentOutOfRangeException)
- {
- throw new ArgumentOutOfRangeException("this descriptor size is less than content size");
- }
-
- if (CalculateDigest(buffer) != descriptor.Digest)
- {
- throw new MismatchedDigestException("this descriptor digest is different from content digest");
- }
- return buffer;
- }
- }
-}
diff --git a/src/OrasProject.Oras/Content/Digest.cs b/src/OrasProject.Oras/Content/Digest.cs
new file mode 100644
index 0000000..28c594b
--- /dev/null
+++ b/src/OrasProject.Oras/Content/Digest.cs
@@ -0,0 +1,51 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using OrasProject.Oras.Exceptions;
+using System;
+using System.Security.Cryptography;
+using System.Text.RegularExpressions;
+
+namespace OrasProject.Oras.Content;
+
+internal static class Digest
+{
+ private const string digestRegexPattern = @"[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+";
+ private static readonly Regex digestRegex = new Regex(digestRegexPattern, RegexOptions.Compiled);
+
+ ///
+ /// Verifies the digest header and throws an exception if it is invalid.
+ ///
+ ///
+ internal static string Validate(string digest)
+ {
+ if (string.IsNullOrEmpty(digest) || !digestRegex.IsMatch(digest))
+ {
+ throw new InvalidDigestException($"Invalid digest: {digest}");
+ }
+ return digest;
+ }
+
+ ///
+ /// Generates a SHA-256 digest from a byte array.
+ ///
+ ///
+ ///
+ internal static string ComputeSHA256(byte[] content)
+ {
+ using var sha256 = SHA256.Create();
+ var hash = sha256.ComputeHash(content);
+ var output = $"sha256:{BitConverter.ToString(hash).Replace("-", "")}";
+ return output.ToLower();
+ }
+}
diff --git a/src/OrasProject.Oras/Content/DigestUtility.cs b/src/OrasProject.Oras/Content/DigestUtility.cs
deleted file mode 100644
index 8614346..0000000
--- a/src/OrasProject.Oras/Content/DigestUtility.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright The ORAS Authors.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OrasProject.Oras.Exceptions;
-using System;
-using System.Security.Cryptography;
-using System.Text.RegularExpressions;
-
-namespace OrasProject.Oras.Content
-{
- internal static class DigestUtility
- {
-
- ///
- /// digestRegexp checks the digest.
- ///
- private const string digestRegexPattern = @"[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+";
- static Regex digestRegex = new Regex(digestRegexPattern, RegexOptions.Compiled);
-
- ///
- /// ParseDigest verifies the digest header and throws an exception if it is invalid.
- ///
- ///
- internal static string ParseDigest(string digest)
- {
- if (!digestRegex.IsMatch(digest))
- {
- throw new InvalidDigestException($"Invalid digest: {digest}");
- }
-
- return digest;
- }
-
- ///
- /// CalculateSHA256DigestFromBytes generates a SHA256 digest from a byte array.
- ///
- ///
- ///
- internal static string CalculateSHA256DigestFromBytes(byte[] content)
- {
- using var sha256 = SHA256.Create();
- var hash = sha256.ComputeHash(content);
- var output = $"{nameof(SHA256)}:{BitConverter.ToString(hash).Replace("-", "")}";
- return output.ToLower();
- }
- }
-}
diff --git a/src/OrasProject.Oras/Content/Extensions.cs b/src/OrasProject.Oras/Content/Extensions.cs
new file mode 100644
index 0000000..3a0b544
--- /dev/null
+++ b/src/OrasProject.Oras/Content/Extensions.cs
@@ -0,0 +1,112 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using OrasProject.Oras.Exceptions;
+using OrasProject.Oras.Oci;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace OrasProject.Oras.Content;
+
+public static class Extensions
+{
+ ///
+ /// Retrieves the successors of a node
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task> SuccessorsAsync(this IFetchable fetcher, Descriptor node, CancellationToken cancellationToken)
+ {
+ switch (node.MediaType)
+ {
+ case Docker.MediaType.Manifest:
+ case Oci.MediaType.ImageManifest:
+ {
+ var content = await fetcher.FetchAllAsync(node, cancellationToken).ConfigureAwait(false);
+ var manifest = JsonSerializer.Deserialize(content);
+ if (manifest == null)
+ {
+ throw new JsonException("null image manifest");
+ }
+ var descriptors = new List() { manifest.Config };
+ descriptors.AddRange(manifest.Layers);
+ return descriptors;
+ }
+ case Docker.MediaType.ManifestList:
+ case Oci.MediaType.ImageIndex:
+ {
+ var content = await fetcher.FetchAllAsync(node, cancellationToken).ConfigureAwait(false);
+ // docker manifest list and oci index are equivalent for successors.
+ var index = JsonSerializer.Deserialize(content);
+ if (index == null)
+ {
+ throw new JsonException("null image index");
+ }
+ return index.Manifests;
+ }
+ }
+ return new List();
+ }
+
+ ///
+ /// Fetches all the content for a given descriptor.
+ /// Currently only sha256 is supported but we would supports others hash algorithms in the future.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task FetchAllAsync(this IFetchable fetcher, Descriptor desc, CancellationToken cancellationToken)
+ {
+ var stream = await fetcher.FetchAsync(desc, cancellationToken).ConfigureAwait(false);
+ return await stream.ReadAllAsync(desc, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// Reads and verifies the content from a stream
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static async Task ReadAllAsync(this Stream stream, Descriptor descriptor, CancellationToken cancellationToken)
+ {
+ if (descriptor.Size < 0)
+ {
+ throw new InvalidDescriptorSizeException("this descriptor size is less than 0");
+ }
+ var buffer = new byte[descriptor.Size];
+ try
+ {
+ await stream.ReadAsync(buffer, 0, (int)stream.Length, cancellationToken).ConfigureAwait(false);
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ throw new ArgumentOutOfRangeException("this descriptor size is less than content size");
+ }
+
+ if (Digest.ComputeSHA256(buffer) != descriptor.Digest)
+ {
+ throw new MismatchedDigestException("this descriptor digest is different from content digest");
+ }
+ return buffer;
+ }
+}
diff --git a/src/OrasProject.Oras/Interfaces/IDeleter.cs b/src/OrasProject.Oras/Content/IDeletable.cs
similarity index 59%
rename from src/OrasProject.Oras/Interfaces/IDeleter.cs
rename to src/OrasProject.Oras/Content/IDeletable.cs
index 72c5824..4cb0536 100644
--- a/src/OrasProject.Oras/Interfaces/IDeleter.cs
+++ b/src/OrasProject.Oras/Content/IDeletable.cs
@@ -11,23 +11,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.Threading;
using System.Threading.Tasks;
-namespace OrasProject.Oras.Interfaces
+namespace OrasProject.Oras.Content;
+
+///
+/// Removes content.
+///
+public interface IDeletable
{
///
- /// IDeleter removes content.
+ /// This deletes content Identified by the descriptor
///
- public interface IDeleter
- {
- ///
- /// This deletes content Identified by the descriptor
- ///
- ///
- ///
- ///
- Task DeleteAsync(Descriptor target, CancellationToken cancellationToken = default);
- }
+ ///
+ ///
+ ///
+ Task DeleteAsync(Descriptor target, CancellationToken cancellationToken = default);
}
diff --git a/src/OrasProject.Oras/Interfaces/IFetcher.cs b/src/OrasProject.Oras/Content/IFetchable.cs
similarity index 58%
rename from src/OrasProject.Oras/Interfaces/IFetcher.cs
rename to src/OrasProject.Oras/Content/IFetchable.cs
index 331f35f..805712c 100644
--- a/src/OrasProject.Oras/Interfaces/IFetcher.cs
+++ b/src/OrasProject.Oras/Content/IFetchable.cs
@@ -11,24 +11,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-namespace OrasProject.Oras.Interfaces
+namespace OrasProject.Oras.Content;
+
+///
+/// Fetches content.
+///
+public interface IFetchable
{
///
- /// IFetcher fetches content.
+ /// FetchAsync fetches the content identified by the descriptor.
///
- public interface IFetcher
- {
- ///
- /// FetchAsync fetches the content identified by the descriptor.
- ///
- ///
- ///
- ///
- Task FetchAsync(Descriptor target, CancellationToken cancellationToken = default);
- }
+ ///
+ ///
+ ///
+ Task FetchAsync(Descriptor target, CancellationToken cancellationToken = default);
}
diff --git a/src/OrasProject.Oras/Content/IPushable.cs b/src/OrasProject.Oras/Content/IPushable.cs
new file mode 100644
index 0000000..800f484
--- /dev/null
+++ b/src/OrasProject.Oras/Content/IPushable.cs
@@ -0,0 +1,35 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using OrasProject.Oras.Oci;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace OrasProject.Oras.Content;
+
+///
+/// Represents a content-addressable storage (CAS) where contents are accessed via Descriptors.
+/// The storage is designed to handle blobs of large sizes.
+///
+public interface IPushable
+{
+ ///
+ /// PushAsync pushes the content, matching the expected descriptor.
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task PushAsync(Descriptor expected, Stream content, CancellationToken cancellationToken = default);
+}
diff --git a/src/OrasProject.Oras/Interfaces/IResolver.cs b/src/OrasProject.Oras/Content/IReadOnlyStorage.cs
similarity index 57%
rename from src/OrasProject.Oras/Interfaces/IResolver.cs
rename to src/OrasProject.Oras/Content/IReadOnlyStorage.cs
index e20e43e..5c34b59 100644
--- a/src/OrasProject.Oras/Interfaces/IResolver.cs
+++ b/src/OrasProject.Oras/Content/IReadOnlyStorage.cs
@@ -11,23 +11,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.Threading;
using System.Threading.Tasks;
-namespace OrasProject.Oras.Interfaces
+namespace OrasProject.Oras.Content;
+
+///
+/// Represents a read-only Storage.
+///
+public interface IReadOnlyStorage : IFetchable
{
///
- /// IResolver resolves reference tags.
+ /// ExistsAsync returns true if the described content exists.
///
- public interface IResolver
- {
- ///
- /// ResolveAsync resolves the reference to a descriptor.
- ///
- ///
- ///
- ///
- Task ResolveAsync(string reference, CancellationToken cancellationToken = default);
- }
+ ///
+ ///
+ ///
+ Task ExistsAsync(Descriptor target, CancellationToken cancellationToken = default);
}
diff --git a/src/OrasProject.Oras/Interfaces/IReadOnlyStorage.cs b/src/OrasProject.Oras/Content/IResolvable.cs
similarity index 56%
rename from src/OrasProject.Oras/Interfaces/IReadOnlyStorage.cs
rename to src/OrasProject.Oras/Content/IResolvable.cs
index 221dfaa..0df68f3 100644
--- a/src/OrasProject.Oras/Interfaces/IReadOnlyStorage.cs
+++ b/src/OrasProject.Oras/Content/IResolvable.cs
@@ -11,23 +11,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.Threading;
using System.Threading.Tasks;
-namespace OrasProject.Oras.Interfaces
+namespace OrasProject.Oras.Content;
+
+///
+/// Resolves reference tags.
+///
+public interface IResolvable
{
///
- /// IReadOnlyStorage represents a read-only Storage.
+ /// ResolveAsync resolves the reference to a descriptor.
///
- public interface IReadOnlyStorage : IFetcher
- {
- ///
- /// ExistsAsync returns true if the described content exists.
- ///
- ///
- ///
- ///
- Task ExistsAsync(Descriptor target, CancellationToken cancellationToken = default);
- }
+ ///
+ ///
+ ///
+ Task ResolveAsync(string reference, CancellationToken cancellationToken = default);
}
diff --git a/src/OrasProject.Oras/Constants/DockerMediaTypes.cs b/src/OrasProject.Oras/Content/IStorage.cs
similarity index 53%
rename from src/OrasProject.Oras/Constants/DockerMediaTypes.cs
rename to src/OrasProject.Oras/Content/IStorage.cs
index 7ed9099..465c7ab 100644
--- a/src/OrasProject.Oras/Constants/DockerMediaTypes.cs
+++ b/src/OrasProject.Oras/Content/IStorage.cs
@@ -11,14 +11,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-namespace OrasProject.Oras.Constants
+namespace OrasProject.Oras.Content;
+
+///
+/// Represents a content-addressable storage (CAS) where contents are accessed via Descriptors.
+/// The storage is designed to handle blobs of large sizes.
+///
+public interface IStorage : IReadOnlyStorage, IPushable
{
- public static class DockerMediaTypes
- {
- // Docker media types
- public const string Config = "application/vnd.docker.container.image.v1+json";
- public const string ManifestList = "application/vnd.docker.distribution.manifest.list.v2+json";
- public const string Manifest = "application/vnd.docker.distribution.manifest.v2+json";
- public const string ForeignLayer = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip";
- }
}
diff --git a/src/OrasProject.Oras/Interfaces/ITagResolver.cs b/src/OrasProject.Oras/Content/ITagStore.cs
similarity index 74%
rename from src/OrasProject.Oras/Interfaces/ITagResolver.cs
rename to src/OrasProject.Oras/Content/ITagStore.cs
index d3476bf..cce032d 100644
--- a/src/OrasProject.Oras/Interfaces/ITagResolver.cs
+++ b/src/OrasProject.Oras/Content/ITagStore.cs
@@ -11,12 +11,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-namespace OrasProject.Oras.Interfaces
+namespace OrasProject.Oras.Content;
+
+///
+/// Provides reference tag indexing services.
+///
+public interface ITagStore : IResolvable, ITaggable
{
- ///
- /// ITagResolver provides reference tag indexing services.
- ///
- public interface ITagResolver : IResolver, ITagger
- {
- }
}
diff --git a/src/OrasProject.Oras/Content/ITaggable.cs b/src/OrasProject.Oras/Content/ITaggable.cs
new file mode 100644
index 0000000..9e3719e
--- /dev/null
+++ b/src/OrasProject.Oras/Content/ITaggable.cs
@@ -0,0 +1,33 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using OrasProject.Oras.Oci;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace OrasProject.Oras.Content;
+
+///
+/// Tags reference tags
+///
+public interface ITaggable
+{
+ ///
+ /// TagAsync tags the descriptor with the reference.
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task TagAsync(Descriptor descriptor, string reference, CancellationToken cancellationToken = default);
+}
diff --git a/src/OrasProject.Oras/Copy.cs b/src/OrasProject.Oras/Copy.cs
index ca3f202..da22acf 100644
--- a/src/OrasProject.Oras/Copy.cs
+++ b/src/OrasProject.Oras/Copy.cs
@@ -12,11 +12,11 @@
// limitations under the License.
using OrasProject.Oras.Interfaces;
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System;
using System.Threading;
using System.Threading.Tasks;
-using static OrasProject.Oras.Content.Content;
+using static OrasProject.Oras.Content.Extensions;
namespace OrasProject.Oras
{
@@ -63,7 +63,7 @@ public static async Task CopyGraphAsync(ITarget src, ITarget dst, Descriptor nod
if (!await dst.ExistsAsync(node, cancellationToken))
{
// retrieve successors
- var successors = await SuccessorsAsync(src, node, cancellationToken);
+ var successors = await src.SuccessorsAsync(node, cancellationToken);
// obtain data stream
var dataStream = await src.FetchAsync(node, cancellationToken);
// check if the node has successors
diff --git a/src/OrasProject.Oras/Docker/MediaType.cs b/src/OrasProject.Oras/Docker/MediaType.cs
new file mode 100644
index 0000000..afa26f4
--- /dev/null
+++ b/src/OrasProject.Oras/Docker/MediaType.cs
@@ -0,0 +1,25 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace OrasProject.Oras.Docker;
+
+///
+/// Docker media types
+///
+public static class MediaType
+{
+ public const string Config = "application/vnd.docker.container.image.v1+json";
+ public const string ManifestList = "application/vnd.docker.distribution.manifest.list.v2+json";
+ public const string Manifest = "application/vnd.docker.distribution.manifest.v2+json";
+ public const string ForeignLayer = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip";
+}
diff --git a/src/OrasProject.Oras/Interfaces/IReadOnlyTarget.cs b/src/OrasProject.Oras/Interfaces/IReadOnlyTarget.cs
index 3219484..db9d675 100644
--- a/src/OrasProject.Oras/Interfaces/IReadOnlyTarget.cs
+++ b/src/OrasProject.Oras/Interfaces/IReadOnlyTarget.cs
@@ -11,12 +11,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using OrasProject.Oras.Content;
+
namespace OrasProject.Oras.Interfaces
{
///
/// IReadOnlyTarget represents a read-only Target.
///
- public interface IReadOnlyTarget : IReadOnlyStorage, IResolver
+ public interface IReadOnlyTarget : IReadOnlyStorage, IResolvable
{
}
}
diff --git a/src/OrasProject.Oras/Interfaces/IStorage.cs b/src/OrasProject.Oras/Interfaces/IStorage.cs
deleted file mode 100644
index 8b1847f..0000000
--- a/src/OrasProject.Oras/Interfaces/IStorage.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright The ORAS Authors.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OrasProject.Oras.Models;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace OrasProject.Oras.Interfaces
-{
- ///
- /// IStorage represents a content-addressable storage (CAS) where contents are accessed via Descriptors.
- /// The storage is designed to handle blobs of large sizes.
- ///
- public interface IStorage : IReadOnlyStorage
- {
- ///
- /// PushAsync pushes the content, matching the expected descriptor.
- ///
- ///
- ///
- ///
- ///
- Task PushAsync(Descriptor expected, Stream content, CancellationToken cancellationToken = default);
- }
-}
diff --git a/src/OrasProject.Oras/Interfaces/ITagger.cs b/src/OrasProject.Oras/Interfaces/ITagger.cs
deleted file mode 100644
index fcf436f..0000000
--- a/src/OrasProject.Oras/Interfaces/ITagger.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright The ORAS Authors.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OrasProject.Oras.Models;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace OrasProject.Oras.Interfaces
-{
- ///
- /// ITagger tags reference tags
- ///
- public interface ITagger
- {
- ///
- /// TagAsync tags the descriptor with the reference.
- ///
- ///
- ///
- ///
- ///
- Task TagAsync(Descriptor descriptor, string reference, CancellationToken cancellationToken = default);
- }
-}
diff --git a/src/OrasProject.Oras/Interfaces/ITarget.cs b/src/OrasProject.Oras/Interfaces/ITarget.cs
index 1efd8a7..8bfa739 100644
--- a/src/OrasProject.Oras/Interfaces/ITarget.cs
+++ b/src/OrasProject.Oras/Interfaces/ITarget.cs
@@ -11,12 +11,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using OrasProject.Oras.Content;
+
namespace OrasProject.Oras.Interfaces
{
///
/// Target is a CAS with generic tags
///
- public interface ITarget : IStorage, ITagResolver
+ public interface ITarget : IStorage, ITagStore
{
}
}
diff --git a/src/OrasProject.Oras/Interfaces/Registry/IBlobStore.cs b/src/OrasProject.Oras/Interfaces/Registry/IBlobStore.cs
index 36d0ba6..0658121 100644
--- a/src/OrasProject.Oras/Interfaces/Registry/IBlobStore.cs
+++ b/src/OrasProject.Oras/Interfaces/Registry/IBlobStore.cs
@@ -11,12 +11,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using OrasProject.Oras.Content;
+
namespace OrasProject.Oras.Interfaces.Registry
{
///
/// IBlobStore is a CAS with the ability to stat and delete its content.
///
- public interface IBlobStore : IStorage, IResolver, IDeleter, IReferenceFetcher
+ public interface IBlobStore : IStorage, IResolvable, IDeletable, IReferenceFetcher
{
}
}
diff --git a/src/OrasProject.Oras/Interfaces/Registry/IManifestStore.cs b/src/OrasProject.Oras/Interfaces/Registry/IManifestStore.cs
index f11284f..35dabcb 100644
--- a/src/OrasProject.Oras/Interfaces/Registry/IManifestStore.cs
+++ b/src/OrasProject.Oras/Interfaces/Registry/IManifestStore.cs
@@ -11,13 +11,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using OrasProject.Oras.Content;
+
namespace OrasProject.Oras.Interfaces.Registry
{
///
/// IManifestStore is a CAS with the ability to stat and delete its content.
/// Besides, IManifestStore provides reference tagging.
///
- public interface IManifestStore : IBlobStore, IReferencePusher, ITagger
+ public interface IManifestStore : IBlobStore, IReferencePusher, ITaggable
{
}
}
diff --git a/src/OrasProject.Oras/Interfaces/Registry/IReferenceFetcher.cs b/src/OrasProject.Oras/Interfaces/Registry/IReferenceFetcher.cs
index e848eef..26d2cc6 100644
--- a/src/OrasProject.Oras/Interfaces/Registry/IReferenceFetcher.cs
+++ b/src/OrasProject.Oras/Interfaces/Registry/IReferenceFetcher.cs
@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
diff --git a/src/OrasProject.Oras/Interfaces/Registry/IReferencePusher.cs b/src/OrasProject.Oras/Interfaces/Registry/IReferencePusher.cs
index b1ad239..1d6fd3c 100644
--- a/src/OrasProject.Oras/Interfaces/Registry/IReferencePusher.cs
+++ b/src/OrasProject.Oras/Interfaces/Registry/IReferencePusher.cs
@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
diff --git a/src/OrasProject.Oras/Interfaces/Registry/IRepository.cs b/src/OrasProject.Oras/Interfaces/Registry/IRepository.cs
index 0032c4e..3a6aa84 100644
--- a/src/OrasProject.Oras/Interfaces/Registry/IRepository.cs
+++ b/src/OrasProject.Oras/Interfaces/Registry/IRepository.cs
@@ -11,6 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using OrasProject.Oras.Content;
+
namespace OrasProject.Oras.Interfaces.Registry
{
///
@@ -25,7 +27,7 @@ namespace OrasProject.Oras.Interfaces.Registry
/// Furthermore, this interface also provides the ability to enforce the
/// separation of the blob and the manifests CASs.
///
- public interface IRepository : ITarget, IReferenceFetcher, IReferencePusher, IDeleter, ITagLister
+ public interface IRepository : ITarget, IReferenceFetcher, IReferencePusher, IDeletable, ITagLister
{
///
/// Blobs provides access to the blob CAS only, which contains config blobs,layers, and other generic blobs.
diff --git a/src/OrasProject.Oras/Memory/MemoryGraph.cs b/src/OrasProject.Oras/Memory/MemoryGraph.cs
index 5f60e91..f2193ef 100644
--- a/src/OrasProject.Oras/Memory/MemoryGraph.cs
+++ b/src/OrasProject.Oras/Memory/MemoryGraph.cs
@@ -11,24 +11,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Interfaces;
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Content;
+using OrasProject.Oras.Oci;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using static OrasProject.Oras.Content.Content;
+using static OrasProject.Oras.Content.Extensions;
namespace OrasProject.Oras.Memory
{
internal class MemoryGraph
{
- private ConcurrentDictionary> _predecessors = new ConcurrentDictionary>();
+ private ConcurrentDictionary> _predecessors = new ConcurrentDictionary>();
- internal async Task IndexAsync(IFetcher fetcher, Descriptor node, CancellationToken cancellationToken)
+ internal async Task IndexAsync(IFetchable fetcher, Descriptor node, CancellationToken cancellationToken)
{
- IList successors = await SuccessorsAsync(fetcher, node, cancellationToken);
+ IList successors = await fetcher.SuccessorsAsync(node, cancellationToken);
Index(node, successors, cancellationToken);
}
@@ -42,8 +42,8 @@ internal async Task IndexAsync(IFetcher fetcher, Descriptor node, CancellationTo
///
internal async Task> PredecessorsAsync(Descriptor node, CancellationToken cancellationToken)
{
- var key = node.GetMinimumDescriptor();
- if (!this._predecessors.TryGetValue(key, out ConcurrentDictionary predecessors))
+ var key = node.BasicDescriptor;
+ if (!this._predecessors.TryGetValue(key, out ConcurrentDictionary predecessors))
{
return default;
}
@@ -66,11 +66,11 @@ private void Index(Descriptor node, IList successors, CancellationTo
return;
}
- var predecessorKey = node.GetMinimumDescriptor();
+ var predecessorKey = node.BasicDescriptor;
foreach (var successor in successors)
{
- var successorKey = successor.GetMinimumDescriptor();
- var predecessors = this._predecessors.GetOrAdd(successorKey, new ConcurrentDictionary());
+ var successorKey = successor.BasicDescriptor;
+ var predecessors = this._predecessors.GetOrAdd(successorKey, new ConcurrentDictionary());
predecessors.TryAdd(predecessorKey, node);
}
diff --git a/src/OrasProject.Oras/Memory/MemoryStorage.cs b/src/OrasProject.Oras/Memory/MemoryStorage.cs
index fd37a6b..ea95ece 100644
--- a/src/OrasProject.Oras/Memory/MemoryStorage.cs
+++ b/src/OrasProject.Oras/Memory/MemoryStorage.cs
@@ -11,24 +11,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using OrasProject.Oras.Content;
using OrasProject.Oras.Exceptions;
-using OrasProject.Oras.Interfaces;
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-using static OrasProject.Oras.Content.Content;
+using static OrasProject.Oras.Content.Extensions;
namespace OrasProject.Oras.Memory
{
internal class MemoryStorage : IStorage
{
- private ConcurrentDictionary _content = new ConcurrentDictionary();
+ private ConcurrentDictionary _content = new ConcurrentDictionary();
public Task ExistsAsync(Descriptor target, CancellationToken cancellationToken)
{
- var contentExist = _content.ContainsKey(target.GetMinimumDescriptor());
+ var contentExist = _content.ContainsKey(target.BasicDescriptor);
return Task.FromResult(contentExist);
}
@@ -36,7 +36,7 @@ public Task ExistsAsync(Descriptor target, CancellationToken cancellationT
public Task FetchAsync(Descriptor target, CancellationToken cancellationToken = default)
{
- var contentExist = this._content.TryGetValue(target.GetMinimumDescriptor(), out byte[] content);
+ var contentExist = this._content.TryGetValue(target.BasicDescriptor, out byte[] content);
if (!contentExist)
{
throw new NotFoundException($"{target.Digest} : {target.MediaType}");
@@ -47,13 +47,13 @@ public Task FetchAsync(Descriptor target, CancellationToken cancellation
public async Task PushAsync(Descriptor expected, Stream contentStream, CancellationToken cancellationToken = default)
{
- var key = expected.GetMinimumDescriptor();
+ var key = expected.BasicDescriptor;
var contentExist = _content.TryGetValue(key, out byte[] _);
if (contentExist)
{
throw new AlreadyExistsException($"{expected.Digest} : {expected.MediaType}");
}
- var readBytes = await ReadAllAsync(contentStream, expected);
+ var readBytes = await contentStream.ReadAllAsync(expected, cancellationToken);
var added = _content.TryAdd(key, readBytes);
if (!added) throw new AlreadyExistsException($"{key.Digest} : {key.MediaType}");
diff --git a/src/OrasProject.Oras/Memory/MemoryTagResolver.cs b/src/OrasProject.Oras/Memory/MemoryTagResolver.cs
index d4bc308..8ac589e 100644
--- a/src/OrasProject.Oras/Memory/MemoryTagResolver.cs
+++ b/src/OrasProject.Oras/Memory/MemoryTagResolver.cs
@@ -11,16 +11,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using OrasProject.Oras.Content;
using OrasProject.Oras.Exceptions;
-using OrasProject.Oras.Interfaces;
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace OrasProject.Oras.Memory
{
- internal class MemoryTagResolver : ITagResolver
+ internal class MemoryTagResolver : ITagStore
{
private ConcurrentDictionary _index = new ConcurrentDictionary();
diff --git a/src/OrasProject.Oras/Memory/MemoryTarget.cs b/src/OrasProject.Oras/Memory/MemoryTarget.cs
index 7b1c429..1a4bdc1 100644
--- a/src/OrasProject.Oras/Memory/MemoryTarget.cs
+++ b/src/OrasProject.Oras/Memory/MemoryTarget.cs
@@ -13,7 +13,7 @@
using OrasProject.Oras.Exceptions;
using OrasProject.Oras.Interfaces;
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.Collections.Generic;
using System.IO;
using System.Threading;
diff --git a/src/OrasProject.Oras/Models/Descriptor.cs b/src/OrasProject.Oras/Models/Descriptor.cs
deleted file mode 100644
index 09dfdcb..0000000
--- a/src/OrasProject.Oras/Models/Descriptor.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright The ORAS Authors.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-
-namespace OrasProject.Oras.Models
-{
- public class Descriptor
- {
- [JsonPropertyName("mediaType")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public string MediaType { get; set; }
-
- [JsonPropertyName("digest")]
- public string Digest { get; set; }
-
- [JsonPropertyName("size")]
- public long Size { get; set; }
-
- [JsonPropertyName("urls")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public IList URLs { get; set; }
-
- [JsonPropertyName("annotations")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public IDictionary Annotations { get; set; }
-
- [JsonPropertyName("data")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public byte[] Data { get; set; }
-
- [JsonPropertyName("platform")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public Platform Platform { get; set; }
-
- [JsonPropertyName("artifactType")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public string ArtifactType { get; set; }
-
- internal MinimumDescriptor GetMinimumDescriptor()
- {
- return new MinimumDescriptor
- {
- MediaType = this.MediaType,
- Digest = this.Digest,
- Size = this.Size
- };
- }
- }
-
- public class Platform
- {
- [JsonPropertyName("architecture")]
- public string Architecture { get; set; }
-
- [JsonPropertyName("os")]
- public string OS { get; set; }
-
- [JsonPropertyName("os.version")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public string OSVersion { get; set; }
-
- [JsonPropertyName("os.features")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public IList OSFeatures { get; set; }
-
- [JsonPropertyName("variant")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public string Variant { get; set; }
- }
-
-}
diff --git a/src/OrasProject.Oras/Models/Index.cs b/src/OrasProject.Oras/Models/Index.cs
deleted file mode 100644
index f493ea1..0000000
--- a/src/OrasProject.Oras/Models/Index.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright The ORAS Authors.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace OrasProject.Oras.Models
-{
- public class Index
- {
- [JsonPropertyName("schemaVersion")]
- public int SchemaVersion { get; set; }
-
- // MediaType specifies the type of this document data structure e.g. `application/vnd.oci.image.index.v1+json`
- [JsonPropertyName("mediaType")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
-
- public string MediaType { get; set; }
-
- // Manifests references platform specific manifests.
- [JsonPropertyName("manifests")]
- public List Manifests { get; set; }
-
- // Annotations contains arbitrary metadata for the image index.
- [JsonPropertyName("annotations")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
-
- public Dictionary Annotations { get; set; }
- }
-}
diff --git a/src/OrasProject.Oras/Models/Manifest.cs b/src/OrasProject.Oras/Models/Manifest.cs
deleted file mode 100644
index 8389daa..0000000
--- a/src/OrasProject.Oras/Models/Manifest.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright The ORAS Authors.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System.Collections.Generic;
-using System.Text.Json.Serialization;
-
-namespace OrasProject.Oras.Models
-{
- public class Manifest
- {
- [JsonPropertyName("schemaVersion")]
- public int SchemaVersion { get; set; }
-
- [JsonPropertyName("mediaType")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public string MediaType { get; set; }
-
- [JsonPropertyName("config")]
- public Descriptor Config { get; set; }
-
- [JsonPropertyName("layers")]
- public List Layers { get; set; }
-
- [JsonPropertyName("annotations")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public Dictionary Annotations { get; set; }
- }
-}
diff --git a/src/OrasProject.Oras/Models/MinimumDescriptor.cs b/src/OrasProject.Oras/Models/MinimumDescriptor.cs
deleted file mode 100644
index 9672a0c..0000000
--- a/src/OrasProject.Oras/Models/MinimumDescriptor.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright The ORAS Authors.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.Text.Json.Serialization;
-
-
-namespace OrasProject.Oras.Models
-{
- internal class MinimumDescriptor : IEquatable
- {
- [JsonPropertyName("mediaType")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
- public string MediaType { get; set; }
-
- [JsonPropertyName("digest")]
- public string Digest { get; set; }
-
- [JsonPropertyName("size")]
- public long Size { get; set; }
-
- public bool Equals(MinimumDescriptor other)
- {
- if (other == null) return false;
- return this.MediaType == other.MediaType && this.Digest == other.Digest && this.Size == other.Size;
- }
-
- public override int GetHashCode()
- {
- return (this.MediaType + this.Digest + this.Size.ToString()).GetHashCode();
- }
- }
-}
diff --git a/src/OrasProject.Oras/Oci/BasicDescriptor.cs b/src/OrasProject.Oras/Oci/BasicDescriptor.cs
new file mode 100644
index 0000000..1b8c6a1
--- /dev/null
+++ b/src/OrasProject.Oras/Oci/BasicDescriptor.cs
@@ -0,0 +1,16 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace OrasProject.Oras.Oci;
+
+internal record BasicDescriptor(string MediaType, string Digest, long Size);
diff --git a/src/OrasProject.Oras/Oci/Descriptor.cs b/src/OrasProject.Oras/Oci/Descriptor.cs
new file mode 100644
index 0000000..9720e15
--- /dev/null
+++ b/src/OrasProject.Oras/Oci/Descriptor.cs
@@ -0,0 +1,51 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace OrasProject.Oras.Oci;
+
+public class Descriptor
+{
+ [JsonPropertyName("mediaType")]
+ public required string MediaType { get; set; }
+
+ [JsonPropertyName("digest")]
+ public required string Digest { get; set; }
+
+ [JsonPropertyName("size")]
+ public long Size { get; set; }
+
+ [JsonPropertyName("urls")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public IList? URLs { get; set; }
+
+ [JsonPropertyName("annotations")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public IDictionary? Annotations { get; set; }
+
+ [JsonPropertyName("data")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public byte[]? Data { get; set; }
+
+ [JsonPropertyName("platform")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public Platform? Platform { get; set; }
+
+ [JsonPropertyName("artifactType")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public string? ArtifactType { get; set; }
+
+ internal BasicDescriptor BasicDescriptor => new BasicDescriptor(MediaType, Digest, Size);
+}
diff --git a/src/OrasProject.Oras/Oci/Index.cs b/src/OrasProject.Oras/Oci/Index.cs
new file mode 100644
index 0000000..e11eff2
--- /dev/null
+++ b/src/OrasProject.Oras/Oci/Index.cs
@@ -0,0 +1,42 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace OrasProject.Oras.Oci;
+
+public class Index : Versioned
+{
+ // MediaType specifies the type of this document data structure e.g. `application/vnd.oci.image.index.v1+json`
+ [JsonPropertyName("mediaType")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public string? MediaType { get; set; }
+
+ [JsonPropertyName("artifactType")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public string? ArtifactType { get; set; }
+
+ // Manifests references platform specific manifests.
+ [JsonPropertyName("manifests")]
+ public required IList Manifests { get; set; }
+
+ [JsonPropertyName("subject")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public Descriptor? Subject { get; set; }
+
+ // Annotations contains arbitrary metadata for the image index.
+ [JsonPropertyName("annotations")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public IDictionary? Annotations { get; set; }
+}
diff --git a/src/OrasProject.Oras/Oci/Manifest.cs b/src/OrasProject.Oras/Oci/Manifest.cs
new file mode 100644
index 0000000..330f17f
--- /dev/null
+++ b/src/OrasProject.Oras/Oci/Manifest.cs
@@ -0,0 +1,42 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace OrasProject.Oras.Oci;
+
+public class Manifest : Versioned
+{
+ [JsonPropertyName("mediaType")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public string? MediaType { get; set; }
+
+ [JsonPropertyName("artifactType")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public string? ArtifactType { get; set; }
+
+ [JsonPropertyName("config")]
+ public required Descriptor Config { get; set; }
+
+ [JsonPropertyName("layers")]
+ public required IList Layers { get; set; }
+
+ [JsonPropertyName("subject")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public Descriptor? Subject { get; set; }
+
+ [JsonPropertyName("annotations")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public IDictionary? Annotations { get; set; }
+}
diff --git a/src/OrasProject.Oras/Oci/MediaType.cs b/src/OrasProject.Oras/Oci/MediaType.cs
new file mode 100644
index 0000000..9026042
--- /dev/null
+++ b/src/OrasProject.Oras/Oci/MediaType.cs
@@ -0,0 +1,84 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace OrasProject.Oras.Oci;
+
+public static class MediaType
+{
+ ///
+ /// Descriptor specifies the media type for a content descriptor.
+ ///
+ public const string Descriptor = "application/vnd.oci.descriptor.v1+json";
+
+ ///
+ /// LayoutHeader specifies the media type for the oci-layout.
+ ///
+ public const string LayoutHeader = "application/vnd.oci.layout.header.v1+json";
+
+ ///
+ /// ImageIndex specifies the media type for an image index.
+ ///
+ public const string ImageIndex = "application/vnd.oci.image.index.v1+json";
+
+ ///
+ /// ImageManifest specifies the media type for an image manifest.
+ ///
+ public const string ImageManifest = "application/vnd.oci.image.manifest.v1+json";
+
+ ///
+ /// ImageConfig specifies the media type for the image configuration.
+ ///
+ public const string ImageConfig = "application/vnd.oci.image.config.v1+json";
+
+ ///
+ /// EmptyJSON specifies the media type for an unused blob containing the value "{}".
+ ///
+ public const string EmptyJson = "application/vnd.oci.empty.v1+json";
+
+ ///
+ /// ImageLayer is the media type used for layers referenced by the manifest.
+ ///
+ public const string ImageLayer = "application/vnd.oci.image.layer.v1.tar";
+
+ ///
+ /// ImageLayerGzip is the media type used for gzipped layers
+ /// referenced by the manifest.
+ ///
+ public const string ImageLayerGzip = "application/vnd.oci.image.layer.v1.tar+gzip";
+
+ ///
+ /// ImageLayerZstd is the media type used for zstd compressed
+ /// layers referenced by the manifest.
+ ///
+ public const string ImageLayerZstd = "application/vnd.oci.image.layer.v1.tar+zstd";
+
+ ///
+ /// ImageLayerNonDistributable is the media type for layers referenced by
+ /// the manifest but with distribution restrictions.
+ ///
+ public const string ImageLayerNonDistributable = "application/vnd.oci.image.layer.nondistributable.v1.tar";
+
+ ///
+ /// ImageLayerNonDistributableGzip is the media type for
+ /// gzipped layers referenced by the manifest but with distribution
+ /// restrictions.
+ ///
+ public const string ImageLayerNonDistributableGzip = "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip";
+
+ ///
+ /// ImageLayerNonDistributableZstd is the media type for zstd
+ /// compressed layers referenced by the manifest but with distribution
+ /// restrictions.
+ ///
+ public const string ImageLayerNonDistributableZstd = "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd";
+}
diff --git a/src/OrasProject.Oras/Oci/Platform.cs b/src/OrasProject.Oras/Oci/Platform.cs
new file mode 100644
index 0000000..2dc417e
--- /dev/null
+++ b/src/OrasProject.Oras/Oci/Platform.cs
@@ -0,0 +1,38 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace OrasProject.Oras.Oci;
+
+public class Platform
+{
+ [JsonPropertyName("architecture")]
+ public required string Architecture { get; set; }
+
+ [JsonPropertyName("os")]
+ public required string OS { get; set; }
+
+ [JsonPropertyName("os.version")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public string? OSVersion { get; set; }
+
+ [JsonPropertyName("os.features")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public IList? OSFeatures { get; set; }
+
+ [JsonPropertyName("variant")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public string? Variant { get; set; }
+}
diff --git a/src/OrasProject.Oras/Oci/Versioned.cs b/src/OrasProject.Oras/Oci/Versioned.cs
new file mode 100644
index 0000000..42d76bd
--- /dev/null
+++ b/src/OrasProject.Oras/Oci/Versioned.cs
@@ -0,0 +1,22 @@
+// Copyright The ORAS Authors.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text.Json.Serialization;
+
+namespace OrasProject.Oras.Oci;
+
+public class Versioned
+{
+ [JsonPropertyName("schemaVersion")]
+ public int SchemaVersion { get; set; }
+}
diff --git a/src/OrasProject.Oras/OrasProject.Oras.csproj b/src/OrasProject.Oras/OrasProject.Oras.csproj
index b987556..9f8b9ef 100644
--- a/src/OrasProject.Oras/OrasProject.Oras.csproj
+++ b/src/OrasProject.Oras/OrasProject.Oras.csproj
@@ -10,6 +10,7 @@
true
README.md
Library
+ enable
diff --git a/src/OrasProject.Oras/Remote/ManifestUtility.cs b/src/OrasProject.Oras/Remote/ManifestUtility.cs
index faa3396..154faa2 100644
--- a/src/OrasProject.Oras/Remote/ManifestUtility.cs
+++ b/src/OrasProject.Oras/Remote/ManifestUtility.cs
@@ -11,8 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Constants;
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.Linq;
namespace OrasProject.Oras.Remote
@@ -21,10 +20,10 @@ internal static class ManifestUtility
{
internal static string[] DefaultManifestMediaTypes = new[]
{
- DockerMediaTypes.Manifest,
- DockerMediaTypes.ManifestList,
- OCIMediaTypes.ImageIndex,
- OCIMediaTypes.ImageManifest
+ Docker.MediaType.Manifest,
+ Docker.MediaType.ManifestList,
+ Oci.MediaType.ImageIndex,
+ Oci.MediaType.ImageManifest
};
///
diff --git a/src/OrasProject.Oras/Remote/RemoteReference.cs b/src/OrasProject.Oras/Remote/RemoteReference.cs
index 56b8857..e13873c 100644
--- a/src/OrasProject.Oras/Remote/RemoteReference.cs
+++ b/src/OrasProject.Oras/Remote/RemoteReference.cs
@@ -11,7 +11,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Content;
using OrasProject.Oras.Exceptions;
using System;
using System.Text.RegularExpressions;
@@ -131,7 +130,7 @@ public static RemoteReference ParseReference(string artifact)
///
public void ValidateReferenceAsDigest()
{
- DigestUtility.ParseDigest(Reference);
+ Content.Digest.Validate(Reference);
}
diff --git a/src/OrasProject.Oras/Remote/Repository.cs b/src/OrasProject.Oras/Remote/Repository.cs
index 3f4dc54..1640d14 100644
--- a/src/OrasProject.Oras/Remote/Repository.cs
+++ b/src/OrasProject.Oras/Remote/Repository.cs
@@ -14,7 +14,7 @@
using OrasProject.Oras.Content;
using OrasProject.Oras.Exceptions;
using OrasProject.Oras.Interfaces.Registry;
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System;
using System.Collections.Generic;
using System.IO;
@@ -363,7 +363,7 @@ internal static void VerifyContentDigest(HttpResponseMessage resp, string expect
string contentDigest;
try
{
- contentDigest = DigestUtility.ParseDigest(digestStr);
+ contentDigest = Digest.Validate(digestStr);
}
catch (Exception)
{
@@ -724,7 +724,7 @@ public async Task GenerateDescriptorAsync(HttpResponseMessage res, R
static async Task CalculateDigestFromResponse(HttpResponseMessage res)
{
var bytes = await res.Content.ReadAsByteArrayAsync();
- return DigestUtility.CalculateSHA256DigestFromBytes(bytes);
+ return Digest.ComputeSHA256(bytes);
}
///
@@ -819,7 +819,7 @@ public BlobStore(Repository repository)
public async Task FetchAsync(Descriptor target, CancellationToken cancellationToken = default)
{
var remoteReference = Repository.RemoteReference;
- DigestUtility.ParseDigest(target.Digest);
+ Digest.Validate(target.Digest);
remoteReference.Reference = target.Digest;
var url = URLUtiliity.BuildRepositoryBlobURL(Repository.PlainHTTP, remoteReference);
var resp = await Repository.HttpClient.GetAsync(url, cancellationToken);
diff --git a/tests/OrasProject.Oras.Tests/ContentTest/ContentTest.cs b/tests/OrasProject.Oras.Tests/ContentTest/ContentTest.cs
index 2da634f..a54b831 100644
--- a/tests/OrasProject.Oras.Tests/ContentTest/ContentTest.cs
+++ b/tests/OrasProject.Oras.Tests/ContentTest/ContentTest.cs
@@ -11,9 +11,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using OrasProject.Oras.Content;
using System.Text;
using Xunit;
-using static OrasProject.Oras.Content.Content;
namespace OrasProject.Oras.Tests.ContentTest
{
@@ -27,7 +27,7 @@ public void VerifiesIfDigestMatches()
{
var helloWorldDigest = "sha256:11d4ddc357e0822968dbfd226b6e1c2aac018d076a54da4f65e1dc8180684ac3";
var content = Encoding.UTF8.GetBytes("helloWorld");
- var calculateHelloWorldDigest = CalculateDigest(content);
+ var calculateHelloWorldDigest = Digest.ComputeSHA256(content);
Assert.Equal(helloWorldDigest, calculateHelloWorldDigest);
}
}
diff --git a/tests/OrasProject.Oras.Tests/CopyTest.cs b/tests/OrasProject.Oras.Tests/CopyTest.cs
index ca95a6c..b4dc607 100644
--- a/tests/OrasProject.Oras.Tests/CopyTest.cs
+++ b/tests/OrasProject.Oras.Tests/CopyTest.cs
@@ -11,13 +11,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Constants;
+using OrasProject.Oras.Content;
using OrasProject.Oras.Memory;
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.Text;
using System.Text.Json;
using Xunit;
-using static OrasProject.Oras.Content.Content;
namespace OrasProject.Oras.Tests
{
@@ -41,7 +40,7 @@ public async Task CanCopyBetweenMemoryTargetsWithTaggedNode()
var desc = new Descriptor
{
MediaType = mediaType,
- Digest = CalculateDigest(blob),
+ Digest = Digest.ComputeSHA256(blob),
Size = blob.Length
};
descs.Add(desc);
@@ -54,12 +53,12 @@ public async Task CanCopyBetweenMemoryTargetsWithTaggedNode()
Layers = layers
};
var manifestBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(manifest));
- appendBlob(OCIMediaTypes.ImageManifest, manifestBytes);
+ appendBlob(MediaType.ImageManifest, manifestBytes);
};
var getBytes = (string data) => Encoding.UTF8.GetBytes(data);
- appendBlob(OCIMediaTypes.ImageConfig, getBytes("config")); // blob 0
- appendBlob(OCIMediaTypes.ImageLayer, getBytes("foo")); // blob 1
- appendBlob(OCIMediaTypes.ImageLayer, getBytes("bar")); // blob 2
+ appendBlob(MediaType.ImageConfig, getBytes("config")); // blob 0
+ appendBlob(MediaType.ImageLayer, getBytes("foo")); // blob 1
+ appendBlob(MediaType.ImageLayer, getBytes("bar")); // blob 2
generateManifest(descs[0], descs.GetRange(1, 2)); // blob 3
for (var i = 0; i < blobs.Count; i++)
@@ -104,7 +103,7 @@ public async Task CanCopyBetweenMemoryTargets()
var desc = new Descriptor
{
MediaType = mediaType,
- Digest = CalculateDigest(blob),
+ Digest = Digest.ComputeSHA256(blob),
Size = blob.Length
};
descs.Add(desc);
@@ -117,12 +116,12 @@ public async Task CanCopyBetweenMemoryTargets()
Layers = layers
};
var manifestBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(manifest));
- appendBlob(OCIMediaTypes.ImageManifest, manifestBytes);
+ appendBlob(MediaType.ImageManifest, manifestBytes);
};
var getBytes = (string data) => Encoding.UTF8.GetBytes(data);
- appendBlob(OCIMediaTypes.ImageConfig, getBytes("config")); // blob 0
- appendBlob(OCIMediaTypes.ImageLayer, getBytes("foo")); // blob 1
- appendBlob(OCIMediaTypes.ImageLayer, getBytes("bar")); // blob 2
+ appendBlob(MediaType.ImageConfig, getBytes("config")); // blob 0
+ appendBlob(MediaType.ImageLayer, getBytes("foo")); // blob 1
+ appendBlob(MediaType.ImageLayer, getBytes("bar")); // blob 2
generateManifest(descs[0], descs.GetRange(1, 2)); // blob 3
for (var i = 0; i < blobs.Count; i++)
diff --git a/tests/OrasProject.Oras.Tests/MemoryTest/MemoryTargetTest.cs b/tests/OrasProject.Oras.Tests/MemoryTest/MemoryTargetTest.cs
index 13f527e..cbc66a8 100644
--- a/tests/OrasProject.Oras.Tests/MemoryTest/MemoryTargetTest.cs
+++ b/tests/OrasProject.Oras.Tests/MemoryTest/MemoryTargetTest.cs
@@ -11,15 +11,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using OrasProject.Oras.Constants;
+using OrasProject.Oras.Content;
using OrasProject.Oras.Exceptions;
using OrasProject.Oras.Memory;
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using System.Text;
using System.Text.Json;
using Xunit;
-using static OrasProject.Oras.Content.Content;
-using Index = OrasProject.Oras.Models.Index;
+using Index = OrasProject.Oras.Oci.Index;
namespace OrasProject.Oras.Tests.MemoryTest
{
@@ -33,7 +32,7 @@ public class MemoryTargetTest
public async Task CanStoreData()
{
var content = Encoding.UTF8.GetBytes("Hello World");
- string hash = CalculateDigest(content);
+ string hash = Digest.ComputeSHA256(content);
var descriptor = new Descriptor
{
MediaType = "test",
@@ -69,7 +68,7 @@ public async Task ThrowsNotFoundExceptionWhenDataIsNotAvailable()
{
var content = Encoding.UTF8.GetBytes("Hello World");
- string hash = CalculateDigest(content);
+ string hash = Digest.ComputeSHA256(content);
var descriptor = new Descriptor
{
MediaType = "test",
@@ -95,7 +94,7 @@ await Assert.ThrowsAsync(async () =>
public async Task ThrowsAlreadyExistsExceptionWhenSameDataIsPushedTwice()
{
var content = Encoding.UTF8.GetBytes("Hello World");
- string hash = CalculateDigest(content);
+ string hash = Digest.ComputeSHA256(content);
var descriptor = new Descriptor
{
MediaType = "test",
@@ -119,7 +118,7 @@ public async Task ThrowsAnErrorWhenABadPushOccurs()
{
var content = Encoding.UTF8.GetBytes("Hello World");
var wrongContent = Encoding.UTF8.GetBytes("Hello World!");
- string hash = CalculateDigest(content);
+ string hash = Digest.ComputeSHA256(content);
var descriptor = new Descriptor
{
MediaType = "test",
@@ -146,7 +145,7 @@ public async Task ThrowsMismatchedDigestExceptionWhenHashInDigestIsDifferentFrom
{
var content = Encoding.UTF8.GetBytes("Hello World");
var wrongContent = Encoding.UTF8.GetBytes("Hello Danny");
- string hash = CalculateDigest(content);
+ string hash = Digest.ComputeSHA256(content);
var descriptor = new Descriptor
{
MediaType = "test",
@@ -180,7 +179,7 @@ public async Task ShouldReturnPredecessorsOfNodes()
var desc = new Descriptor
{
MediaType = mediaType,
- Digest = CalculateDigest(blob),
+ Digest = Digest.ComputeSHA256(blob),
Size = blob.Length
};
descs.Add(desc);
@@ -193,7 +192,7 @@ public async Task ShouldReturnPredecessorsOfNodes()
Layers = layers
};
var manifestBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(manifest));
- appendBlob(OCIMediaTypes.ImageManifest, manifestBytes);
+ appendBlob(MediaType.ImageManifest, manifestBytes);
};
var generateIndex = (List manifests) =>
@@ -203,13 +202,13 @@ public async Task ShouldReturnPredecessorsOfNodes()
Manifests = manifests
};
var indexBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(index));
- appendBlob(OCIMediaTypes.ImageIndex, indexBytes);
+ appendBlob(MediaType.ImageIndex, indexBytes);
};
var getBytes = (string data) => Encoding.UTF8.GetBytes(data);
- appendBlob(OCIMediaTypes.ImageConfig, getBytes("config")); // blob 0
- appendBlob(OCIMediaTypes.ImageLayer, getBytes("foo")); // blob 1
- appendBlob(OCIMediaTypes.ImageLayer, getBytes("bar")); // blob 2
- appendBlob(OCIMediaTypes.ImageLayer, getBytes("hello")); // blob 3
+ appendBlob(MediaType.ImageConfig, getBytes("config")); // blob 0
+ appendBlob(MediaType.ImageLayer, getBytes("foo")); // blob 1
+ appendBlob(MediaType.ImageLayer, getBytes("bar")); // blob 2
+ appendBlob(MediaType.ImageLayer, getBytes("hello")); // blob 3
generateManifest(descs[0], descs.GetRange(1, 2)); // blob 4
generateManifest(descs[0], new() { descs[3] }); // blob 5
generateManifest(descs[0], descs.GetRange(1, 3)); // blob 6
diff --git a/tests/OrasProject.Oras.Tests/RemoteTest/RepositoryTest.cs b/tests/OrasProject.Oras.Tests/RemoteTest/RepositoryTest.cs
index d487348..be8f626 100644
--- a/tests/OrasProject.Oras.Tests/RemoteTest/RepositoryTest.cs
+++ b/tests/OrasProject.Oras.Tests/RemoteTest/RepositoryTest.cs
@@ -13,10 +13,10 @@
using Moq;
using Moq.Protected;
-using OrasProject.Oras.Constants;
+using OrasProject.Oras.Content;
using OrasProject.Oras.Exceptions;
using OrasProject.Oras.Memory;
-using OrasProject.Oras.Models;
+using OrasProject.Oras.Oci;
using OrasProject.Oras.Remote;
using System.Collections.Immutable;
using System.Diagnostics;
@@ -27,8 +27,7 @@
using System.Text.RegularExpressions;
using System.Web;
using Xunit;
-using static OrasProject.Oras.Content.Content;
-using static OrasProject.Oras.Content.DigestUtility;
+using static OrasProject.Oras.Content.Digest;
namespace OrasProject.Oras.Tests.RemoteTest
{
@@ -168,15 +167,15 @@ public async Task Repository_FetchAsync()
var blob = Encoding.UTF8.GetBytes("hello world");
var blobDesc = new Descriptor()
{
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
MediaType = "test",
Size = (uint)blob.Length
};
var index = """{"manifests":[]}"""u8.ToArray();
var indexDesc = new Descriptor()
{
- Digest = CalculateDigest(index),
- MediaType = OCIMediaTypes.ImageIndex,
+ Digest = ComputeSHA256(index),
+ MediaType = MediaType.ImageIndex,
Size = index.Length
};
var func = (HttpRequestMessage req, CancellationToken cancellationToken) =>
@@ -201,7 +200,7 @@ public async Task Repository_FetchAsync()
if (path == "/v2/test/manifests/" + indexDesc.Digest)
{
- if (!req.Headers.Accept.Contains(new MediaTypeWithQualityHeaderValue(OCIMediaTypes.ImageIndex)))
+ if (!req.Headers.Accept.Contains(new MediaTypeWithQualityHeaderValue(MediaType.ImageIndex)))
{
resp.StatusCode = HttpStatusCode.BadRequest;
Debug.WriteLine("manifest not convertable: " + req.Headers.Accept);
@@ -242,15 +241,15 @@ public async Task Repository_PushAsync()
var blob = @"hello world"u8.ToArray();
var blobDesc = new Descriptor()
{
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
MediaType = "test",
Size = (uint)blob.Length
};
var index = @"{""manifests"":[]}"u8.ToArray();
var indexDesc = new Descriptor()
{
- Digest = CalculateDigest(index),
- MediaType = OCIMediaTypes.ImageIndex,
+ Digest = ComputeSHA256(index),
+ MediaType = MediaType.ImageIndex,
Size = index.Length
};
var uuid = Guid.NewGuid().ToString();
@@ -296,7 +295,7 @@ public async Task Repository_PushAsync()
req.RequestUri!.AbsolutePath == "/v2/test/manifests/" + indexDesc.Digest)
{
if (req.Headers.TryGetValues("Content-Type", out var values) &&
- !values.Contains(OCIMediaTypes.ImageIndex))
+ !values.Contains(MediaType.ImageIndex))
{
resp.StatusCode = HttpStatusCode.BadRequest;
return resp;
@@ -334,15 +333,15 @@ public async Task Repository_ExistsAsync()
var blob = @"hello world"u8.ToArray();
var blobDesc = new Descriptor()
{
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
MediaType = "test",
Size = (uint)blob.Length
};
var index = @"{""manifests"":[]}"u8.ToArray();
var indexDesc = new Descriptor()
{
- Digest = CalculateDigest(index),
- MediaType = OCIMediaTypes.ImageIndex,
+ Digest = ComputeSHA256(index),
+ MediaType = MediaType.ImageIndex,
Size = index.Length
};
var func = (HttpRequestMessage req, CancellationToken cancellationToken) =>
@@ -365,7 +364,7 @@ public async Task Repository_ExistsAsync()
if (req.RequestUri!.AbsolutePath == "/v2/test/manifests/" + indexDesc.Digest)
{
if (req.Headers.TryGetValues("Accept", out var values) &&
- !values.Contains(OCIMediaTypes.ImageIndex))
+ !values.Contains(MediaType.ImageIndex))
{
return new HttpResponseMessage(HttpStatusCode.NotAcceptable);
}
@@ -398,7 +397,7 @@ public async Task Repository_DeleteAsync()
var blob = @"hello world"u8.ToArray();
var blobDesc = new Descriptor()
{
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
MediaType = "test",
Size = (uint)blob.Length
};
@@ -406,8 +405,8 @@ public async Task Repository_DeleteAsync()
var index = @"{""manifests"":[]}"u8.ToArray();
var indexDesc = new Descriptor()
{
- Digest = CalculateDigest(index),
- MediaType = OCIMediaTypes.ImageIndex,
+ Digest = ComputeSHA256(index),
+ MediaType = MediaType.ImageIndex,
Size = index.Length
};
var indexDeleted = false;
@@ -458,15 +457,15 @@ public async Task Repository_ResolveAsync()
var blob = @"hello world"u8.ToArray();
var blobDesc = new Descriptor()
{
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
MediaType = "test",
Size = (uint)blob.Length
};
var index = @"{""manifests"":[]}"u8.ToArray();
var indexDesc = new Descriptor()
{
- Digest = CalculateDigest(index),
- MediaType = OCIMediaTypes.ImageIndex,
+ Digest = ComputeSHA256(index),
+ MediaType = MediaType.ImageIndex,
Size = index.Length
};
var reference = "foobar";
@@ -490,7 +489,7 @@ public async Task Repository_ResolveAsync()
{
if (req.Headers.TryGetValues("Accept", out var values) &&
- !values.Contains(OCIMediaTypes.ImageIndex))
+ !values.Contains(MediaType.ImageIndex))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
@@ -533,15 +532,15 @@ public async Task Repository_TagAsync()
var blob = "hello"u8.ToArray();
var blobDesc = new Descriptor()
{
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
MediaType = "test",
Size = (uint)blob.Length
};
var index = @"{""manifests"":[]}"u8.ToArray();
var indexDesc = new Descriptor()
{
- Digest = CalculateDigest(index),
- MediaType = OCIMediaTypes.ImageIndex,
+ Digest = ComputeSHA256(index),
+ MediaType = MediaType.ImageIndex,
Size = index.Length
};
byte[]? gotIndex = null;
@@ -561,7 +560,7 @@ public async Task Repository_TagAsync()
req.RequestUri?.AbsolutePath == "/v2/test/manifests/" + indexDesc.Digest)
{
if (req.Headers.TryGetValues("Accept", out var values) &&
- !values.Contains(OCIMediaTypes.ImageIndex))
+ !values.Contains(MediaType.ImageIndex))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
@@ -577,7 +576,7 @@ public async Task Repository_TagAsync()
{
if (req.Headers.TryGetValues("Content-Type", out var values) &&
- !values.Contains(OCIMediaTypes.ImageIndex))
+ !values.Contains(MediaType.ImageIndex))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
@@ -615,8 +614,8 @@ public async Task Repository_PushReferenceAsync()
var index = @"{""manifests"":[]}"u8.ToArray();
var indexDesc = new Descriptor()
{
- Digest = CalculateDigest(index),
- MediaType = OCIMediaTypes.ImageIndex,
+ Digest = ComputeSHA256(index),
+ MediaType = MediaType.ImageIndex,
Size = index.Length
};
byte[]? gotIndex = null;
@@ -629,7 +628,7 @@ public async Task Repository_PushReferenceAsync()
if (req.Method == HttpMethod.Put && req.RequestUri?.AbsolutePath == "/v2/test/manifests/" + reference)
{
if (req.Headers.TryGetValues("Content-Type", out var values) &&
- !values.Contains(OCIMediaTypes.ImageIndex))
+ !values.Contains(MediaType.ImageIndex))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
@@ -664,15 +663,15 @@ public async Task Repository_FetchReferenceAsyc()
var blob = "hello"u8.ToArray();
var blobDesc = new Descriptor()
{
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
MediaType = "test",
Size = (uint)blob.Length
};
var index = @"{""manifests"":[]}"u8.ToArray();
var indexDesc = new Descriptor()
{
- Digest = CalculateDigest(index),
- MediaType = OCIMediaTypes.ImageIndex,
+ Digest = ComputeSHA256(index),
+ MediaType = MediaType.ImageIndex,
Size = index.Length
};
var reference = "foobar";
@@ -695,7 +694,7 @@ public async Task Repository_FetchReferenceAsyc()
|| req.RequestUri?.AbsolutePath == "/v2/test/manifests/" + reference)
{
if (req.Headers.TryGetValues("Accept", out var values) &&
- !values.Contains(OCIMediaTypes.ImageIndex))
+ !values.Contains(MediaType.ImageIndex))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
@@ -845,7 +844,7 @@ public async Task BlobStore_FetchAsync()
var blobDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
Size = blob.Length
};
var func = (HttpRequestMessage req, CancellationToken cancellationToken) =>
@@ -891,7 +890,7 @@ public async Task BlobStore_FetchAsync_CanSeek()
var blobDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
Size = blob.Length
};
var seekable = false;
@@ -992,7 +991,7 @@ public async Task BlobStore_FetchAsync_ZeroSizedBlob()
var blobDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
Size = blob.Length
};
var func = (HttpRequestMessage req, CancellationToken cancellationToken) =>
@@ -1041,7 +1040,7 @@ public async Task BlobStore_PushAsync()
var blobDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
Size = blob.Length
};
var gotBlob = new byte[blob.Length];
@@ -1100,14 +1099,14 @@ public async Task BlobStore_ExistsAsync()
var blobDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
Size = blob.Length
};
var content = "foobar"u8.ToArray();
var contentDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(content),
+ Digest = ComputeSHA256(content),
Size = content.Length
};
var func = (HttpRequestMessage req, CancellationToken cancellationToken) =>
@@ -1152,7 +1151,7 @@ public async Task BlobStore_DeleteAsync()
var blobDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
Size = blob.Length
};
var blobDeleted = false;
@@ -1188,7 +1187,7 @@ public async Task BlobStore_DeleteAsync()
var contentDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(content),
+ Digest = ComputeSHA256(content),
Size = content.Length
};
await Assert.ThrowsAsync(async () => await store.DeleteAsync(contentDesc, cancellationToken));
@@ -1205,7 +1204,7 @@ public async Task BlobStore_ResolveAsync()
var blobDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
Size = blob.Length
};
var func = (HttpRequestMessage req, CancellationToken cancellationToken) =>
@@ -1245,7 +1244,7 @@ public async Task BlobStore_ResolveAsync()
var contentDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(content),
+ Digest = ComputeSHA256(content),
Size = content.Length
};
await Assert.ThrowsAsync(async () =>
@@ -1263,7 +1262,7 @@ public async Task BlobStore_FetchReferenceAsync()
var blobDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
Size = blob.Length
};
var func = (HttpRequestMessage req, CancellationToken cancellationToken) =>
@@ -1312,7 +1311,7 @@ public async Task BlobStore_FetchReferenceAsync()
var contentDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(content),
+ Digest = ComputeSHA256(content),
Size = content.Length
};
// test with other digest
@@ -1331,7 +1330,7 @@ public async Task BlobStore_FetchReferenceAsync_Seek()
var blobDesc = new Descriptor()
{
MediaType = "test",
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
Size = blob.Length
};
var seekable = false;
@@ -1522,8 +1521,8 @@ public async Task ManifestStore_FetchAsync()
var manifest = """{"layers":[]}"""u8.ToArray();
var manifestDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageManifest,
- Digest = CalculateDigest(manifest),
+ MediaType = MediaType.ImageManifest,
+ Digest = ComputeSHA256(manifest),
Size = manifest.Length
};
@@ -1537,12 +1536,12 @@ public async Task ManifestStore_FetchAsync()
}
if (req.RequestUri?.AbsolutePath == $"/v2/test/manifests/{manifestDesc.Digest}")
{
- if (req.Headers.TryGetValues("Accept", out IEnumerable? values) && !values.Contains(OCIMediaTypes.ImageManifest))
+ if (req.Headers.TryGetValues("Accept", out IEnumerable? values) && !values.Contains(MediaType.ImageManifest))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
res.Content = new ByteArrayContent(manifest);
- res.Content.Headers.Add("Content-Type", new string[] { OCIMediaTypes.ImageManifest });
+ res.Content.Headers.Add("Content-Type", new string[] { MediaType.ImageManifest });
res.Content.Headers.Add("Docker-Content-Digest", new string[] { manifestDesc.Digest });
return res;
}
@@ -1561,8 +1560,8 @@ public async Task ManifestStore_FetchAsync()
var content = """{"manifests":[]}"""u8.ToArray();
var contentDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageIndex,
- Digest = CalculateDigest(content),
+ MediaType = MediaType.ImageIndex,
+ Digest = ComputeSHA256(content),
Size = content.Length
};
await Assert.ThrowsAsync(async () => await store.FetchAsync(contentDesc, cancellationToken));
@@ -1578,8 +1577,8 @@ public async Task ManifestStore_PushAsync()
var manifest = """{"layers":[]}"""u8.ToArray();
var manifestDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageManifest,
- Digest = CalculateDigest(manifest),
+ MediaType = MediaType.ImageManifest,
+ Digest = ComputeSHA256(manifest),
Size = manifest.Length
};
byte[]? gotManifest = null;
@@ -1590,7 +1589,7 @@ public async Task ManifestStore_PushAsync()
res.RequestMessage = req;
if (req.Method == HttpMethod.Put && req.RequestUri?.AbsolutePath == $"/v2/test/manifests/{manifestDesc.Digest}")
{
- if (req.Headers.TryGetValues("Content-Type", out IEnumerable? values) && !values.Contains(OCIMediaTypes.ImageManifest))
+ if (req.Headers.TryGetValues("Content-Type", out IEnumerable? values) && !values.Contains(MediaType.ImageManifest))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
@@ -1629,8 +1628,8 @@ public async Task ManifestStore_ExistAsync()
var manifest = """{"layers":[]}"""u8.ToArray();
var manifestDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageManifest,
- Digest = CalculateDigest(manifest),
+ MediaType = MediaType.ImageManifest,
+ Digest = ComputeSHA256(manifest),
Size = manifest.Length
};
var func = (HttpRequestMessage req, CancellationToken cancellationToken) =>
@@ -1643,12 +1642,12 @@ public async Task ManifestStore_ExistAsync()
}
if (req.RequestUri?.AbsolutePath == $"/v2/test/manifests/{manifestDesc.Digest}")
{
- if (req.Headers.TryGetValues("Accept", out IEnumerable? values) && !values.Contains(OCIMediaTypes.ImageManifest))
+ if (req.Headers.TryGetValues("Accept", out IEnumerable? values) && !values.Contains(MediaType.ImageManifest))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
res.Content.Headers.Add("Docker-Content-Digest", new string[] { manifestDesc.Digest });
- res.Content.Headers.Add("Content-Type", new string[] { OCIMediaTypes.ImageManifest });
+ res.Content.Headers.Add("Content-Type", new string[] { MediaType.ImageManifest });
res.Content.Headers.Add("Content-Length", new string[] { manifest.Length.ToString() });
return res;
}
@@ -1665,8 +1664,8 @@ public async Task ManifestStore_ExistAsync()
var content = """{"manifests":[]}"""u8.ToArray();
var contentDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageIndex,
- Digest = CalculateDigest(content),
+ MediaType = MediaType.ImageIndex,
+ Digest = ComputeSHA256(content),
Size = content.Length
};
exist = await store.ExistsAsync(contentDesc, cancellationToken);
@@ -1683,8 +1682,8 @@ public async Task ManifestStore_DeleteAsync()
var manifest = """{"layers":[]}"""u8.ToArray();
var manifestDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageManifest,
- Digest = CalculateDigest(manifest),
+ MediaType = MediaType.ImageManifest,
+ Digest = ComputeSHA256(manifest),
Size = manifest.Length
};
var manifestDeleted = false;
@@ -1704,13 +1703,13 @@ public async Task ManifestStore_DeleteAsync()
}
if (req.Method == HttpMethod.Get && req.RequestUri?.AbsolutePath == $"/v2/test/manifests/{manifestDesc.Digest}")
{
- if (req.Headers.TryGetValues("Accept", out IEnumerable? values) && !values.Contains(OCIMediaTypes.ImageManifest))
+ if (req.Headers.TryGetValues("Accept", out IEnumerable? values) && !values.Contains(MediaType.ImageManifest))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
res.Content = new ByteArrayContent(manifest);
res.Content.Headers.Add("Docker-Content-Digest", new string[] { manifestDesc.Digest });
- res.Content.Headers.Add("Content-Type", new string[] { OCIMediaTypes.ImageManifest });
+ res.Content.Headers.Add("Content-Type", new string[] { MediaType.ImageManifest });
return res;
}
return new HttpResponseMessage(HttpStatusCode.NotFound);
@@ -1726,8 +1725,8 @@ public async Task ManifestStore_DeleteAsync()
var content = """{"manifests":[]}"""u8.ToArray();
var contentDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageIndex,
- Digest = CalculateDigest(content),
+ MediaType = MediaType.ImageIndex,
+ Digest = ComputeSHA256(content),
Size = content.Length
};
await Assert.ThrowsAsync(async () => await store.DeleteAsync(contentDesc, cancellationToken));
@@ -1743,8 +1742,8 @@ public async Task ManifestStore_ResolveAsync()
var manifest = """{"layers":[]}"""u8.ToArray();
var manifestDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageManifest,
- Digest = CalculateDigest(manifest),
+ MediaType = MediaType.ImageManifest,
+ Digest = ComputeSHA256(manifest),
Size = manifest.Length
};
var reference = "foobar";
@@ -1758,12 +1757,12 @@ public async Task ManifestStore_ResolveAsync()
}
if (req.RequestUri?.AbsolutePath == $"/v2/test/manifests/{manifestDesc.Digest}" || req.RequestUri?.AbsolutePath == $"/v2/test/manifests/{reference}")
{
- if (req.Headers.TryGetValues("Accept", out IEnumerable? values) && !values.Contains(OCIMediaTypes.ImageManifest))
+ if (req.Headers.TryGetValues("Accept", out IEnumerable? values) && !values.Contains(MediaType.ImageManifest))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
res.Content.Headers.Add("Docker-Content-Digest", new string[] { manifestDesc.Digest });
- res.Content.Headers.Add("Content-Type", new string[] { OCIMediaTypes.ImageManifest });
+ res.Content.Headers.Add("Content-Type", new string[] { MediaType.ImageManifest });
res.Content.Headers.Add("Content-Length", new string[] { manifest.Length.ToString() });
return res;
}
@@ -1790,8 +1789,8 @@ public async Task ManifestStore_ResolveAsync()
var content = """{"manifests":[]}"""u8.ToArray();
var contentDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageIndex,
- Digest = CalculateDigest(content),
+ MediaType = MediaType.ImageIndex,
+ Digest = ComputeSHA256(content),
Size = content.Length
};
@@ -1809,8 +1808,8 @@ public async Task ManifestStore_FetchReferenceAsync()
var manifest = """{"layers":[]}"""u8.ToArray();
var manifestDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageManifest,
- Digest = CalculateDigest(manifest),
+ MediaType = MediaType.ImageManifest,
+ Digest = ComputeSHA256(manifest),
Size = manifest.Length
};
var reference = "foobar";
@@ -1824,13 +1823,13 @@ public async Task ManifestStore_FetchReferenceAsync()
}
if (req.RequestUri?.AbsolutePath == $"/v2/test/manifests/{manifestDesc.Digest}" || req.RequestUri?.AbsolutePath == $"/v2/test/manifests/{reference}")
{
- if (req.Headers.TryGetValues("Accept", out IEnumerable? values) && !values.Contains(OCIMediaTypes.ImageManifest))
+ if (req.Headers.TryGetValues("Accept", out IEnumerable? values) && !values.Contains(MediaType.ImageManifest))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
res.Content = new ByteArrayContent(manifest);
res.Content.Headers.Add("Docker-Content-Digest", new string[] { manifestDesc.Digest });
- res.Content.Headers.Add("Content-Type", new string[] { OCIMediaTypes.ImageManifest });
+ res.Content.Headers.Add("Content-Type", new string[] { MediaType.ImageManifest });
return res;
}
return new HttpResponseMessage(HttpStatusCode.NotFound);
@@ -1888,14 +1887,14 @@ public async Task ManifestStore_TagAsync()
var blobDesc = new Descriptor
{
MediaType = "test",
- Digest = CalculateDigest(blob),
+ Digest = ComputeSHA256(blob),
Size = blob.Length
};
var index = """{"manifests":[]}"""u8.ToArray();
var indexDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageIndex,
- Digest = CalculateDigest(index),
+ MediaType = MediaType.ImageIndex,
+ Digest = ComputeSHA256(index),
Size = index.Length
};
var gotIndex = new byte[index.Length];
@@ -1930,8 +1929,8 @@ public async Task ManifestStore_TagAsync()
}
if (req.Content?.Headers?.ContentLength != null)
{
- var buf = new byte[req.Content.Headers.ContentLength.Value];
- (await req.Content.ReadAsByteArrayAsync()).CopyTo(buf, 0);
+ var buf = new byte[req.Content.Headers.ContentLength.Value];
+ (await req.Content.ReadAsByteArrayAsync()).CopyTo(buf, 0);
gotIndex = buf;
}
@@ -1970,8 +1969,8 @@ public async Task ManifestStore_PushReferenceAsync()
var index = """{"manifests":[]}"""u8.ToArray();
var indexDesc = new Descriptor
{
- MediaType = OCIMediaTypes.ImageIndex,
- Digest = CalculateDigest(index),
+ MediaType = MediaType.ImageIndex,
+ Digest = ComputeSHA256(index),
Size = index.Length
};
var gotIndex = new byte[index.Length];
@@ -2024,8 +2023,8 @@ public async Task CopyFromRepositoryToMemory()
var exampleManifestDescriptor = new Descriptor
{
- MediaType = OCIMediaTypes.Descriptor,
- Digest = CalculateSHA256DigestFromBytes(exampleManifest),
+ MediaType = MediaType.Descriptor,
+ Digest = Digest.ComputeSHA256(exampleManifest),
Size = exampleManifest.Length
};
var exampleUploadUUid = new Guid().ToString();
@@ -2039,7 +2038,7 @@ public async Task CopyFromRepositoryToMemory()
{
res.StatusCode = HttpStatusCode.Accepted;
res.Headers.Location = new Uri($"{path}/{exampleUploadUUid}");
- res.Headers.Add("Content-Type", OCIMediaTypes.ImageManifest);
+ res.Headers.Add("Content-Type", MediaType.ImageManifest);
return res;
}
if (path.Contains("/blobs/uploads/" + exampleUploadUUid) && method == HttpMethod.Get)
@@ -2059,12 +2058,12 @@ public async Task CopyFromRepositoryToMemory()
if (method == HttpMethod.Get)
{
res.Content = new ByteArrayContent(exampleManifest);
- res.Content.Headers.Add("Content-Type", OCIMediaTypes.Descriptor);
+ res.Content.Headers.Add("Content-Type", MediaType.Descriptor);
res.Content.Headers.Add("Docker-Content-Digest", exampleManifestDescriptor.Digest);
res.Content.Headers.Add("Content-Length", exampleManifest.Length.ToString());
return res;
}
- res.Content.Headers.Add("Content-Type", OCIMediaTypes.Descriptor);
+ res.Content.Headers.Add("Content-Type", MediaType.Descriptor);
res.Content.Headers.Add("Docker-Content-Digest", exampleManifestDescriptor.Digest);
res.Content.Headers.Add("Content-Length", exampleManifest.Length.ToString());
return res;