using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;
using StabilityMatrix.Core.Processes;
namespace StabilityMatrix.Core.Python;
public partial record PipPackageSpecifier
{
public required string Name { get; init; }
public string? Constraint { get; init; }
public string? Version { get; init; }
public string? VersionConstraint => Constraint is null || Version is null ? null : Constraint + Name;
public static PipPackageSpecifier Parse(string value)
{
var result = TryParse(value, true, out var packageSpecifier);
Debug.Assert(result);
return packageSpecifier!;
}
public static bool TryParse(string value, [NotNullWhen(true)] out PipPackageSpecifier? packageSpecifier)
{
return TryParse(value, false, out packageSpecifier);
}
private static bool TryParse(
string value,
bool throwOnFailure,
[NotNullWhen(true)] out PipPackageSpecifier? packageSpecifier
)
{
var match = PackageSpecifierRegex().Match(value);
if (!match.Success)
{
if (throwOnFailure)
{
throw new ArgumentException($"Invalid package specifier: {value}");
}
packageSpecifier = null;
return false;
}
packageSpecifier = new PipPackageSpecifier
{
Name = match.Groups["package_name"].Value,
Constraint = match.Groups["version_constraint"].Value,
Version = match.Groups["version"].Value
};
return true;
}
///
public override string ToString()
{
return Name + VersionConstraint;
}
public static implicit operator Argument(PipPackageSpecifier specifier)
{
return specifier.VersionConstraint is null
? new Argument(specifier.Name)
: new Argument((specifier.Name, specifier.VersionConstraint));
}
public static implicit operator PipPackageSpecifier(string specifier)
{
return Parse(specifier);
}
///
/// Regex to match a pip package specifier.
///
[GeneratedRegex(
"(?[a-zA-Z0-9_]+)(?(?==|>=|<=|>|<|~=|!=)([a-zA-Z0-9_.]+))?",
RegexOptions.CultureInvariant,
1000
)]
private static partial Regex PackageSpecifierRegex();
}