Restructure solution layout by module
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Docs CI / lint-and-preview (push) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Docs CI / lint-and-preview (push) Has been cancelled
				
			This commit is contained in:
		@@ -0,0 +1,264 @@
 | 
			
		||||
namespace StellaOps.Concelier.Merge.Comparers;
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using StellaOps.Concelier.Normalization.Distro;
 | 
			
		||||
 | 
			
		||||
public sealed class NevraComparer : IComparer<Nevra>, IComparer<string>
 | 
			
		||||
{
 | 
			
		||||
    public static NevraComparer Instance { get; } = new();
 | 
			
		||||
 | 
			
		||||
    private NevraComparer()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int Compare(string? x, string? y)
 | 
			
		||||
    {
 | 
			
		||||
        if (ReferenceEquals(x, y))
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (x is null)
 | 
			
		||||
        {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (y is null)
 | 
			
		||||
        {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var xParsed = Nevra.TryParse(x, out var xNevra);
 | 
			
		||||
        var yParsed = Nevra.TryParse(y, out var yNevra);
 | 
			
		||||
 | 
			
		||||
        if (xParsed && yParsed)
 | 
			
		||||
        {
 | 
			
		||||
            return Compare(xNevra, yNevra);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (xParsed)
 | 
			
		||||
        {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (yParsed)
 | 
			
		||||
        {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return string.Compare(x, y, StringComparison.Ordinal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int Compare(Nevra? x, Nevra? y)
 | 
			
		||||
    {
 | 
			
		||||
        if (ReferenceEquals(x, y))
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (x is null)
 | 
			
		||||
        {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (y is null)
 | 
			
		||||
        {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var compare = string.Compare(x.Name, y.Name, StringComparison.Ordinal);
 | 
			
		||||
        if (compare != 0)
 | 
			
		||||
        {
 | 
			
		||||
            return compare;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        compare = string.Compare(x.Architecture ?? string.Empty, y.Architecture ?? string.Empty, StringComparison.Ordinal);
 | 
			
		||||
        if (compare != 0)
 | 
			
		||||
        {
 | 
			
		||||
            return compare;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        compare = x.Epoch.CompareTo(y.Epoch);
 | 
			
		||||
        if (compare != 0)
 | 
			
		||||
        {
 | 
			
		||||
            return compare;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        compare = RpmVersionComparer.Compare(x.Version, y.Version);
 | 
			
		||||
        if (compare != 0)
 | 
			
		||||
        {
 | 
			
		||||
            return compare;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        compare = RpmVersionComparer.Compare(x.Release, y.Release);
 | 
			
		||||
        if (compare != 0)
 | 
			
		||||
        {
 | 
			
		||||
            return compare;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return string.Compare(x.Original, y.Original, StringComparison.Ordinal);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal static class RpmVersionComparer
 | 
			
		||||
{
 | 
			
		||||
    public static int Compare(string? left, string? right)
 | 
			
		||||
    {
 | 
			
		||||
        left ??= string.Empty;
 | 
			
		||||
        right ??= string.Empty;
 | 
			
		||||
 | 
			
		||||
        var i = 0;
 | 
			
		||||
        var j = 0;
 | 
			
		||||
 | 
			
		||||
        while (true)
 | 
			
		||||
        {
 | 
			
		||||
            var leftHasTilde = SkipToNextSegment(left, ref i);
 | 
			
		||||
            var rightHasTilde = SkipToNextSegment(right, ref j);
 | 
			
		||||
 | 
			
		||||
            if (leftHasTilde || rightHasTilde)
 | 
			
		||||
            {
 | 
			
		||||
                if (leftHasTilde && rightHasTilde)
 | 
			
		||||
                {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return leftHasTilde ? -1 : 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var leftEnd = i >= left.Length;
 | 
			
		||||
            var rightEnd = j >= right.Length;
 | 
			
		||||
            if (leftEnd || rightEnd)
 | 
			
		||||
            {
 | 
			
		||||
                if (leftEnd && rightEnd)
 | 
			
		||||
                {
 | 
			
		||||
                    return 0;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return leftEnd ? -1 : 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var leftDigit = char.IsDigit(left[i]);
 | 
			
		||||
            var rightDigit = char.IsDigit(right[j]);
 | 
			
		||||
 | 
			
		||||
            if (leftDigit && !rightDigit)
 | 
			
		||||
            {
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!leftDigit && rightDigit)
 | 
			
		||||
            {
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int compare;
 | 
			
		||||
            if (leftDigit)
 | 
			
		||||
            {
 | 
			
		||||
                compare = CompareNumericSegment(left, ref i, right, ref j);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                compare = CompareAlphaSegment(left, ref i, right, ref j);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (compare != 0)
 | 
			
		||||
            {
 | 
			
		||||
                return compare;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static bool SkipToNextSegment(string value, ref int index)
 | 
			
		||||
    {
 | 
			
		||||
        var sawTilde = false;
 | 
			
		||||
        while (index < value.Length)
 | 
			
		||||
        {
 | 
			
		||||
            var current = value[index];
 | 
			
		||||
            if (current == '~')
 | 
			
		||||
            {
 | 
			
		||||
                sawTilde = true;
 | 
			
		||||
                index++;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (char.IsLetterOrDigit(current))
 | 
			
		||||
            {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            index++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return sawTilde;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static int CompareNumericSegment(string value, ref int index, string other, ref int otherIndex)
 | 
			
		||||
    {
 | 
			
		||||
        var start = index;
 | 
			
		||||
        while (index < value.Length && char.IsDigit(value[index]))
 | 
			
		||||
        {
 | 
			
		||||
            index++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var otherStart = otherIndex;
 | 
			
		||||
        while (otherIndex < other.Length && char.IsDigit(other[otherIndex]))
 | 
			
		||||
        {
 | 
			
		||||
            otherIndex++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var trimmedStart = start;
 | 
			
		||||
        while (trimmedStart < index && value[trimmedStart] == '0')
 | 
			
		||||
        {
 | 
			
		||||
            trimmedStart++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var otherTrimmedStart = otherStart;
 | 
			
		||||
        while (otherTrimmedStart < otherIndex && other[otherTrimmedStart] == '0')
 | 
			
		||||
        {
 | 
			
		||||
            otherTrimmedStart++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var length = index - trimmedStart;
 | 
			
		||||
        var otherLength = otherIndex - otherTrimmedStart;
 | 
			
		||||
 | 
			
		||||
        if (length != otherLength)
 | 
			
		||||
        {
 | 
			
		||||
            return length.CompareTo(otherLength);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var comparison = value.AsSpan(trimmedStart, length)
 | 
			
		||||
            .CompareTo(other.AsSpan(otherTrimmedStart, otherLength), StringComparison.Ordinal);
 | 
			
		||||
        if (comparison != 0)
 | 
			
		||||
        {
 | 
			
		||||
            return comparison;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static int CompareAlphaSegment(string value, ref int index, string other, ref int otherIndex)
 | 
			
		||||
    {
 | 
			
		||||
        var start = index;
 | 
			
		||||
        while (index < value.Length && char.IsLetter(value[index]))
 | 
			
		||||
        {
 | 
			
		||||
            index++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var otherStart = otherIndex;
 | 
			
		||||
        while (otherIndex < other.Length && char.IsLetter(other[otherIndex]))
 | 
			
		||||
        {
 | 
			
		||||
            otherIndex++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var length = index - start;
 | 
			
		||||
        var otherLength = otherIndex - otherStart;
 | 
			
		||||
 | 
			
		||||
        var comparison = value.AsSpan(start, length)
 | 
			
		||||
            .CompareTo(other.AsSpan(otherStart, otherLength), StringComparison.Ordinal);
 | 
			
		||||
        if (comparison != 0)
 | 
			
		||||
        {
 | 
			
		||||
            return comparison;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user