| File: ProductCollection.cs | Web Access |
| Project: src\deployment-tools\src\Microsoft.Deployment.DotNet.Releases\src\Microsoft.Deployment.DotNet.Releases.csproj (Microsoft.Deployment.DotNet.Releases) |
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Text.Json; using System.Threading.Tasks; namespace Microsoft.Deployment.DotNet.Releases { /// <summary> /// A collection of all released products. /// </summary> public sealed class ProductCollection : ReadOnlyCollection<Product> { /// <summary> /// The default URL of the releases index file. /// </summary> public static readonly Uri ReleasesIndexDefaultUrl = new Uri("https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json"); /// <summary> /// Creates a new <see cref="ProductCollection"/> instance. /// </summary> /// <param name="productList">The list of products to include.</param> private ProductCollection(IList<Product> productList) : base(productList) { } /// <summary> /// Gets an enumerable of all the support phases across all products. /// </summary> public IEnumerable<SupportPhase> GetSupportPhases() { return this.Select(p => p.SupportPhase).Distinct(); } /// <summary> /// Creates a new collection of all released products using the default URL for the releases index file. /// </summary> /// <returns>A collection of products described in the releases index file.</returns> public static async Task<ProductCollection> GetAsync() { return await GetAsync(ReleasesIndexDefaultUrl).ConfigureAwait(false); } /// <summary> /// Creates a new collection of all released products using the provided URL for the releases index file. /// </summary> /// <param name="releasesIndexUri">A string containing the URL pointing to the releases index file.</param> /// <returns>A collection of products described in the releases index file.</returns> public static async Task<ProductCollection> GetAsync(string releasesIndexUri) { if (releasesIndexUri is null) { throw new ArgumentNullException(nameof(releasesIndexUri)); } if (releasesIndexUri == string.Empty) { throw new ArgumentException(ReleasesResources.ValueCannotBeEmpty, nameof(releasesIndexUri)); } return await GetAsync(new Uri(releasesIndexUri)).ConfigureAwait(false); } /// <summary> /// Creates a new collection of all released products using the provided URL for the releases index file. /// </summary> /// <param name="releasesIndexUrl">A URL pointing to the releases index file.</param> /// <returns>A collection of products described in releases index file.</returns> public static async Task<ProductCollection> GetAsync(Uri releasesIndexUrl) { if (releasesIndexUrl == null) { throw new ArgumentNullException(nameof(releasesIndexUrl)); } using var stream = new MemoryStream(await Utils.s_httpClient.GetByteArrayAsync(releasesIndexUrl).ConfigureAwait(false)); return await GetAsync(stream).ConfigureAwait(false); } /// <summary> /// Creates a new <see cref="ProductCollection"/> using the specified file containing the releases index. If /// the file does not exist or is outdated, a newer copy can optionally be downloaded. If the file exist and a /// newer copy is available it will replace the existing local copy. /// </summary> /// <param name="path">The path of the releases index file.</param> /// <param name="downloadLatest">When <see langword="true"/>, if the local copy of the index is /// outdated, or does not exist, a new copy is downloaded, replacing the local copy before processing the file. /// Otherwise, the local copy is used.</param> /// <returns>A collection of all products described by the index.</returns> /// <exception cref="FileNotFoundException">If <paramref name="downloadLatest"/> is <see langword="false"/> and /// <paramref name="path"/> does not exist. /// </exception> public static async Task<ProductCollection> GetFromFileAsync(string path, bool downloadLatest) { await Utils.GetLatestFileAsync(path, downloadLatest, ReleasesIndexDefaultUrl).ConfigureAwait(false); using FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true); return await GetAsync(stream).ConfigureAwait(false); } private static async Task<ProductCollection> GetAsync(Stream stream) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } using var releasesIndexDocument = await JsonDocument.ParseAsync(stream).ConfigureAwait(false); var root = releasesIndexDocument.RootElement.GetProperty("releases-index"); var products = new List<Product>(); using JsonElement.ArrayEnumerator enumerator = root.EnumerateArray(); while (enumerator.MoveNext()) { products.Add(new(enumerator.Current)); } return new ProductCollection(products); } } }