Skip to content

Commit

Permalink
add version sort feature
Browse files Browse the repository at this point in the history
  • Loading branch information
AlphaBs committed Nov 7, 2021
1 parent 3433493 commit 9524a13
Show file tree
Hide file tree
Showing 4 changed files with 320 additions and 3 deletions.
15 changes: 13 additions & 2 deletions CmlLib/Core/Version/MVersionCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CmlLib.Core.VersionMetadata;

Expand Down Expand Up @@ -62,7 +63,12 @@ public MVersionMetadata GetVersionMetadata(string name)

return versionMetadata;
}


public MVersionMetadata[] ToArray(MVersionSortOption option)
{
var sorter = new MVersionMetadataSorter(option);
return sorter.Sort(this);
}

public virtual MVersion GetVersion(string name)
{
Expand Down Expand Up @@ -129,10 +135,15 @@ public virtual async Task<MVersion> GetVersionAsync(MVersionMetadata versionMeta
.ConfigureAwait(false);
startVersion.InheritFrom(baseVersion);
}

return startVersion;
}

public void AddVersion(MVersionMetadata version)
{
Versions[version.Name] = version;
}

public bool Contains(string? versionName)
=> !string.IsNullOrEmpty(versionName) && Versions.Contains(versionName);

Expand Down
181 changes: 181 additions & 0 deletions CmlLib/Core/Version/MVersionSort.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using CmlLib.Core.VersionMetadata;

namespace CmlLib.Core.Version
{
public enum MVersionSortPropertyOption
{
Name,
Version,
ReleaseDate
}

public enum MVersionNullReleaseDateSortOption
{
AsLatest,
AsOldest
}

public class MVersionSortOption
{
public MVersionType[] TypeOrder { get; set; } =
{
MVersionType.Custom,
MVersionType.Release,
MVersionType.Snapshot,
MVersionType.OldBeta,
MVersionType.OldAlpha
};

public MVersionSortPropertyOption PropertyOrderBy { get; set; }
= MVersionSortPropertyOption.Version;

public bool AscendingPropertyOrder { get; set; } = true;

public MVersionNullReleaseDateSortOption NullReleaseDateSortOption { get; set; } =
MVersionNullReleaseDateSortOption.AsOldest;

public bool CustomAsRelease { get; set; } = false;
public bool TypeClassification { get; set; } = true;
}

public class MVersionMetadataSorter
{
public MVersionMetadataSorter(MVersionSortOption option)
{
this.option = option;

this.typePriority = new Dictionary<MVersionType, int>();
for (int i = 0; i < option.TypeOrder.Length; i++)
{
var type = option.TypeOrder[i];
typePriority[type] = i;
}

var propertyList = new List<MVersionSortPropertyOption>();
propertyList.Add(option.PropertyOrderBy);
foreach (MVersionSortPropertyOption item in Enum.GetValues(typeof(MVersionSortPropertyOption)))
{
if (option.PropertyOrderBy != item)
propertyList.Add(item);
}

propertyOptions = propertyList.ToArray();

switch (option.NullReleaseDateSortOption)
{
case MVersionNullReleaseDateSortOption.AsLatest:
defaultDateTime = DateTime.MaxValue;
break;
case MVersionNullReleaseDateSortOption.AsOldest:
defaultDateTime = DateTime.MinValue;
break;
}
}

private readonly MVersionSortPropertyOption[] propertyOptions;
private readonly DateTime defaultDateTime;
private readonly Dictionary<MVersionType, int> typePriority;
private readonly MVersionSortOption option;

public MVersionMetadata[] Sort(IEnumerable<MVersionMetadata> org)
{
var filtered = org.Where(x => getTypePriority(x.MType) >= 0)
.ToArray();
Array.Sort(filtered, compare);
return filtered;
}

private int getTypePriority(MVersionType type)
{
if (option.CustomAsRelease && type == MVersionType.Custom)
type = MVersionType.Release;

if (typePriority.TryGetValue(type, out int p))
return p;

return -1;
}

private int compareType(MVersionMetadata v1, MVersionMetadata v2)
{
var v1TypePrior = getTypePriority(v1.MType);
var v2TypePrior = getTypePriority(v2.MType);
return v1TypePrior - v2TypePrior;
}

private int compareName(MVersionMetadata v1, MVersionMetadata v2)
{
var result = string.CompareOrdinal(v1.Name, v2.Name);
if (!option.AscendingPropertyOrder)
result *= -1;
return result;
}

private int compareVersion(MVersionMetadata v1, MVersionMetadata v2)
{
bool v1r = System.Version.TryParse(v1.Name, out System.Version v1v);
bool v2r = System.Version.TryParse(v2.Name, out System.Version v2v);

if (!v1r && !v2r)
return 0;
if (!v1r) // v1 > v2
return 1;
if (!v2r) // v1 < v2
return -1;

var result = v1v.CompareTo(v2v);
if (!option.AscendingPropertyOrder)
result *= -1;
return result;
}

private int compareReleaseDate(MVersionMetadata v1, MVersionMetadata v2)
{
var v1DateTime = v1.ReleaseTime ?? defaultDateTime;
var v2DateTime = v2.ReleaseTime ?? defaultDateTime;
var result = DateTime.Compare(v1DateTime, v2DateTime);
if (!option.AscendingPropertyOrder)
result *= -1;
return result;
}

private int compareProperty(MVersionMetadata v1, MVersionMetadata v2,
MVersionSortPropertyOption propertyOption)
{
switch (propertyOption)
{
case MVersionSortPropertyOption.Name:
return compareName(v1, v2);
case MVersionSortPropertyOption.ReleaseDate:
return compareReleaseDate(v1, v2);
case MVersionSortPropertyOption.Version:
return compareVersion(v1, v2);
}

return 0;
}

private int compare(MVersionMetadata v1, MVersionMetadata v2)
{
var typeCompareResult = compareType(v1, v2);

if (option.TypeClassification && typeCompareResult != 0)
return typeCompareResult;

foreach (var propOption in propertyOptions)
{
int result = compareProperty(v1, v2, propOption);
if (result != 0)
return result;
}

return typeCompareResult;
}
}
}
12 changes: 11 additions & 1 deletion CmlLib/Core/VersionMetadata/MVersionMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,18 @@ protected MVersionMetadata(string id)

public MVersionType MType { get; set; }

[JsonProperty("releaseTime")] public string? ReleaseTime { get; set; }
[JsonProperty("releaseTime")] public string? ReleaseTimeStr { get; set; }

public DateTime? ReleaseTime
{
get
{
if (DateTime.TryParse(this.ReleaseTimeStr, out DateTime dt))
return dt;
return null;
}
}

[JsonProperty("url")] public string? Path { get; set; }

public override bool Equals(object? obj)
Expand Down
115 changes: 115 additions & 0 deletions CmlLib/Utils/SemiVersion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System.Linq;

namespace CmlLib.Utils
{
public class SemiVersion
{
public bool IsPreRelease { get; private set; }
public int Major { get; private set; }
public int Minor { get; private set; }
public int Patch { get; private set; }
public string Tag { get; private set; } = "";

public int ToInt()
{
return Major * 100 + Minor * 10 + Patch;
}

public override int GetHashCode()
{
return ToInt();
}

public override bool Equals(object obj)
{
if (obj is SemiVersion ver)
return ToInt() == ver.ToInt();
if (obj is int num)
return ToInt() == num;
if (obj is string verStr)
return ToInt() == Parse(verStr)?.ToInt();

return false;
}

public override string ToString()
{
var ver = $"{Major}.{Minor}.{Patch}";
if (IsPreRelease)
ver += "-pre";
return ver;
}

public static SemiVersion? Parse(string version)
{
var semiVer = new SemiVersion();

version = version.Trim();
if (char.IsLetter(version[0]))
{
semiVer.IsPreRelease = true;
version = version.Substring(1);
}

var verSplit = version.Split('.');
if (verSplit.Length <= 1)
return null;

var last = verSplit[verSplit.Length - 1];
var lastCharArr = last.ToCharArray();
int versionEndPosition = 0;
for (; versionEndPosition < last.Length; versionEndPosition++)
{
if (!char.IsDigit(lastCharArr[versionEndPosition]))
{
if (versionEndPosition == 0)
return null; // invalid version
break;
}
}

verSplit[verSplit.Length - 1] = last.Substring(0, versionEndPosition + 1);

if (versionEndPosition > last.Length - 1)
semiVer.Tag = last.Substring(versionEndPosition + 1);

if (!int.TryParse(verSplit[0], out int major))
return null;

if (!int.TryParse(verSplit[1], out int minor))
return null;

int patch = 0;
if (verSplit.Length > 2 && !int.TryParse(verSplit[2], out patch))
return null;

semiVer.Major = major;
semiVer.Minor = minor;
semiVer.Patch = patch;
return semiVer;
}

public static int operator <(SemiVersion v1, SemiVersion v2)
{
var v1Ver = v1.ToInt();
var v2Ver = v2.ToInt();

if (v1Ver == v2Ver)
{
if (v1.IsPreRelease && v2.IsPreRelease)
return 0;
if (v1.IsPreRelease)
return -1;
if (v2.IsPreRelease)
return 1;
}

return v1Ver - v2Ver;
}

public static int operator >(SemiVersion v1, SemiVersion v2)
{
return (v1 < v2) * -1;
}
}
}

0 comments on commit 9524a13

Please sign in to comment.