File: Utils\ContainerReferenceParser.cs
Web Access
Project: src\src\Aspire.Hosting\Aspire.Hosting.csproj (Aspire.Hosting)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text.RegularExpressions;
 
namespace Aspire.Hosting.Utils;
 
/// <summary>
/// Class to parse container references (e.g. "mcr.microsoft.com/dotnet/sdk:8.0")
/// </summary>
internal partial class ContainerReferenceParser
{
    public static ContainerReference Parse(string input)
    {
        if (string.IsNullOrEmpty(input))
        {
            throw new ArgumentOutOfRangeException(nameof(input), "repository name must have at least one component");
        }
 
        var match = ImageNameRegex().Match(input);
 
        if (!match.Success)
        {
            throw new ArgumentOutOfRangeException(nameof(input), input, "invalid reference format: could not parse container image name");
        }
 
        return new(
            GetGroupValueOrDefault(match.Groups["registry"]),
            match.Groups["image"].Value,
            GetGroupValueOrDefault(match.Groups["tag"]),
            GetGroupValueOrDefault(match.Groups["digest"])
            );
 
        static string? GetGroupValueOrDefault(Group group)
            => group.Success ? group.Value : default;
    }
 
    // Based on https://github.com/microsoft/vscode-docker-extensibility/blob/46d92f93d620de74b6505bf9fc391af592fee2db/packages/vscode-container-client/src/utils/parseDockerLikeImageName.ts#L22
    // with addition of ipv6 registries
    [GeneratedRegex("^((?<registry>((localhost|\\[(?:[a-fA-F0-9:]+)\\]|([\\w-]+(\\.[\\w-]+)+))(:\\d+)?)|([\\w-]+:\\d+))\\/)?(?<image>[\\w-./<>]+)(:(?<tag>[\\w-.<>]+))?(@(?<digest>.+))?$")]
    private static partial Regex ImageNameRegex();
}
 
internal record struct ContainerReference(string? Registry, string Image, string? Tag, string? Digest)
{
}