118 lines
4.2 KiB
C#
118 lines
4.2 KiB
C#
#nullable enable
|
|
|
|
using System;
|
|
|
|
namespace ShrinkSDK.Installer
|
|
{
|
|
public enum ShrinkPackageVersionRelation
|
|
{
|
|
Unknown,
|
|
Older,
|
|
Equal,
|
|
Newer
|
|
}
|
|
|
|
public static class ShrinkPackageVersion
|
|
{
|
|
public static ShrinkPackageVersionRelation Classify(string? installedVersion, string? targetVersion)
|
|
{
|
|
return TryCompare(installedVersion, targetVersion, out var comparison)
|
|
? comparison < 0
|
|
? ShrinkPackageVersionRelation.Older
|
|
: comparison > 0
|
|
? ShrinkPackageVersionRelation.Newer
|
|
: ShrinkPackageVersionRelation.Equal
|
|
: ShrinkPackageVersionRelation.Unknown;
|
|
}
|
|
|
|
public static bool TryCompare(string? left, string? right, out int comparison)
|
|
{
|
|
comparison = 0;
|
|
if (!TryParse(left, out var leftVersion) || !TryParse(right, out var rightVersion))
|
|
return false;
|
|
|
|
for (var index = 0; index < 3; index++)
|
|
{
|
|
comparison = leftVersion.Core[index].CompareTo(rightVersion.Core[index]);
|
|
if (comparison != 0)
|
|
return true;
|
|
}
|
|
|
|
comparison = ComparePrerelease(leftVersion.Prerelease, rightVersion.Prerelease);
|
|
return true;
|
|
}
|
|
|
|
private static bool TryParse(string? raw, out ParsedVersion version)
|
|
{
|
|
version = default;
|
|
if (string.IsNullOrWhiteSpace(raw))
|
|
return false;
|
|
|
|
var value = raw.Trim();
|
|
if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase))
|
|
value = value.Substring(1);
|
|
var buildIndex = value.IndexOf('+');
|
|
if (buildIndex >= 0)
|
|
value = value.Substring(0, buildIndex);
|
|
var prereleaseIndex = value.IndexOf('-');
|
|
var coreText = prereleaseIndex >= 0 ? value.Substring(0, prereleaseIndex) : value;
|
|
var prerelease = prereleaseIndex >= 0 ? value.Substring(prereleaseIndex + 1) : string.Empty;
|
|
var coreParts = coreText.Split('.');
|
|
if (coreParts.Length is < 1 or > 3)
|
|
return false;
|
|
|
|
var core = new int[3];
|
|
for (var index = 0; index < coreParts.Length; index++)
|
|
{
|
|
if (!int.TryParse(coreParts[index], out core[index]) || core[index] < 0)
|
|
return false;
|
|
}
|
|
|
|
if (prereleaseIndex >= 0 && string.IsNullOrWhiteSpace(prerelease))
|
|
return false;
|
|
version = new ParsedVersion(core, prerelease);
|
|
return true;
|
|
}
|
|
|
|
private static int ComparePrerelease(string left, string right)
|
|
{
|
|
var leftEmpty = string.IsNullOrEmpty(left);
|
|
var rightEmpty = string.IsNullOrEmpty(right);
|
|
if (leftEmpty || rightEmpty)
|
|
return leftEmpty == rightEmpty ? 0 : leftEmpty ? 1 : -1;
|
|
|
|
var leftParts = left.Split('.');
|
|
var rightParts = right.Split('.');
|
|
var count = Math.Min(leftParts.Length, rightParts.Length);
|
|
for (var index = 0; index < count; index++)
|
|
{
|
|
var leftNumeric = int.TryParse(leftParts[index], out var leftValue);
|
|
var rightNumeric = int.TryParse(rightParts[index], out var rightValue);
|
|
int comparison;
|
|
if (leftNumeric && rightNumeric)
|
|
comparison = leftValue.CompareTo(rightValue);
|
|
else if (leftNumeric != rightNumeric)
|
|
comparison = leftNumeric ? -1 : 1;
|
|
else
|
|
comparison = string.Compare(leftParts[index], rightParts[index], StringComparison.Ordinal);
|
|
if (comparison != 0)
|
|
return comparison;
|
|
}
|
|
|
|
return leftParts.Length.CompareTo(rightParts.Length);
|
|
}
|
|
|
|
private readonly struct ParsedVersion
|
|
{
|
|
public ParsedVersion(int[] core, string prerelease)
|
|
{
|
|
Core = core;
|
|
Prerelease = prerelease;
|
|
}
|
|
|
|
public int[] Core { get; }
|
|
public string Prerelease { get; }
|
|
}
|
|
}
|
|
}
|