Skip to content

Commit

Permalink
fix pre-release version ordering when it contains numeric release-lab…
Browse files Browse the repository at this point in the history
…els + seperate available updates by manually installed
  • Loading branch information
JoC0de committed Dec 14, 2023
1 parent 441f6df commit 93784ca
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 55 deletions.
1 change: 1 addition & 0 deletions src/NuGetForUnity.Tests/Assets/Tests/Editor/NuGetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ public void InstallBouncyCastleTest([Values] InstallMode installMode)
[TestCase("1.2.3-rc1+1234", "1.2.3-rc2")]
[TestCase("1.2.3-rc1+1234", "1.2.3-rc2+1234")]
[TestCase("1.0.0", "1.0.0.10")]
[TestCase("1.0.0-beta.9", "1.0.0-beta.10")]
public void VersionComparison(string smallerVersion, string greaterVersion)
{
var localNugetPackageSource = new NugetPackageSourceLocal("test", "test");
Expand Down
11 changes: 10 additions & 1 deletion src/NuGetForUnity/Editor/Models/NugetPackageIdentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ public override bool Equals(object obj)
Justification = "We only edit the version / id before we use the hash (stroe it in a dictionary).")]
public override int GetHashCode()
{
return Id.GetHashCode() ^ PackageVersion.GetHashCode();
return GetHashCodeOfId() ^ PackageVersion.GetHashCode();
}

/// <summary>
Expand All @@ -280,5 +280,14 @@ public override string ToString()
{
return $"{Id}.{Version}";
}

private int GetHashCodeOfId()
{
#if UNITY_2021_2_OR_NEWER
return Id.GetHashCode(StringComparison.OrdinalIgnoreCase);
#else
return StringComparer.OrdinalIgnoreCase.GetHashCode(Id);
#endif
}
}
}
92 changes: 87 additions & 5 deletions src/NuGetForUnity/Editor/Models/NugetPackageVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,9 @@ private readonly struct SemVer2Version

private readonly int patch;

[CanBeNull]
private readonly string[] preReleaseLabels;

private readonly int revision;

/// <summary>
Expand All @@ -465,6 +468,7 @@ public SemVer2Version(bool dummy)
minor = -1;
patch = -1;
revision = -1;
preReleaseLabels = null;
}

/// <summary>
Expand All @@ -486,10 +490,12 @@ public SemVer2Version([CanBeNull] string version)
}

PreRelease = null;
preReleaseLabels = null;
var preReleaseStartIndex = version.IndexOf('-');
if (preReleaseStartIndex > 0)
{
PreRelease = version.Substring(preReleaseStartIndex + 1);
preReleaseLabels = PreRelease.Split('.');

version = version.Substring(0, preReleaseStartIndex);
}
Expand Down Expand Up @@ -524,6 +530,7 @@ public SemVer2Version([CanBeNull] string version)

buildMetadata = null;
PreRelease = null;
preReleaseLabels = null;
major = -1;
minor = -1;
patch = -1;
Expand Down Expand Up @@ -566,9 +573,24 @@ public int Compare(in SemVer2Version other)
if (revisionComparison == 0)
{
// if the build versions are equal, just return the prerelease version comparison
var prerelease = PreRelease ?? "\uFFFF";
var otherPrerelease = other.PreRelease ?? "\uFFFF";
var prereleaseComparison = string.Compare(prerelease, otherPrerelease, StringComparison.OrdinalIgnoreCase);
if (preReleaseLabels == null && other.preReleaseLabels == null)
{
// no pre-release and the rest is equal
return 0;
}

if (preReleaseLabels != null && other.preReleaseLabels == null)
{
// pre-release versions are always after release versions
return -1;
}

if (preReleaseLabels == null && other.preReleaseLabels != null)
{
return 1;
}

var prereleaseComparison = ComparePreReleaseLabels(preReleaseLabels, other.preReleaseLabels);
return prereleaseComparison;
}

Expand All @@ -587,9 +609,9 @@ public int Compare(in SemVer2Version other)
// the major versions are different, so use them
return majorComparison;
}
catch (Exception)
catch (Exception exception)
{
Debug.LogErrorFormat("Compare Error: {0} {1}", this, other);
Debug.LogErrorFormat("Error: {0} while comparing '{1}' with '{2}'.", exception, this, other);
return -1;
}
}
Expand Down Expand Up @@ -637,6 +659,66 @@ public string ToString(bool withBuildMetadata)

return stringBuilder.ToString();
}

/// <summary>
/// Compares sets of Pre-Release labels (<see cref="PreRelease" /> splitted by '.').
/// </summary>
private static int ComparePreReleaseLabels([NotNull] string[] releaseLabels1, [NotNull] string[] releaseLabels2)
{
var result = 0;

var count = Math.Max(releaseLabels1.Length, releaseLabels2.Length);

for (var i = 0; i < count; i++)
{
var hasLabel1 = i < releaseLabels1.Length;
var hasLabel2 = i < releaseLabels2.Length;

if (!hasLabel1 && hasLabel2)
{
return -1;
}

if (hasLabel1 && !hasLabel2)
{
return 1;
}

// compare the labels
result = ComparePreReleaseLabel(releaseLabels1[i], releaseLabels2[i]);

if (result != 0)
{
return result;
}
}

return result;
}

/// <summary>
/// Pre-Release labels are compared as numbers if they are numeric, otherwise they will be compared as strings (case insensitive).
/// </summary>
private static int ComparePreReleaseLabel(string releaseLabel1, string releaseLabel2)
{
var label1IsNumeric = int.TryParse(releaseLabel1, out var releaseLabel1Number);
var label2IsNumeric = int.TryParse(releaseLabel2, out var releaseLabel2Number);

if (label1IsNumeric && label2IsNumeric)
{
// if both are numeric compare them as numbers
return releaseLabel1Number.CompareTo(releaseLabel2Number);
}

if (label1IsNumeric || label2IsNumeric)
{
// numeric labels come before alpha labels
return label1IsNumeric ? -1 : 1;
}

// Everything will be compared case insensitively.
return string.Compare(releaseLabel1, releaseLabel2, StringComparison.OrdinalIgnoreCase);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -302,24 +302,26 @@ private List<INugetPackage> GetLocalPackages(
}

/// <summary>
/// Gets a list of available packages from a local source (not a web server) that are upgrades for the given list of installed packages.
/// Gets a list of available packages from a local source (not a web server) that are versions / upgrade or downgrade of the given list of installed
/// packages.
/// </summary>
/// <param name="packages">The list of packages to use to find updates.</param>
/// <param name="includePrerelease">True to include prerelease packages (alpha, beta, etc).</param>
/// <returns>A list of all updates available.</returns>
/// <returns>A list of all updates / downgrades available.</returns>
[NotNull]
[ItemNotNull]
private List<INugetPackage> GetLocalUpdates([NotNull] [ItemNotNull] IEnumerable<INugetPackage> packages, bool includePrerelease = false)
{
var updates = new List<INugetPackage>();
foreach (var installedPackage in packages)
foreach (var packageToSearch in packages)
{
var availablePackages = GetLocalPackages($"{installedPackage.Id}*", false, includePrerelease);
var availablePackages = GetLocalPackages($"{packageToSearch.Id}*", false, includePrerelease);
foreach (var availablePackage in availablePackages)
{
if (installedPackage.Id.Equals(availablePackage.Id, StringComparison.OrdinalIgnoreCase) &&
installedPackage.CompareTo(availablePackage) < 0)
if (packageToSearch.Id.Equals(availablePackage.Id, StringComparison.OrdinalIgnoreCase))
{
// keep the manually installed state
availablePackage.IsManuallyInstalled = packageToSearch.IsManuallyInstalled;
updates.Add(availablePackage);
}
}
Expand Down
12 changes: 12 additions & 0 deletions src/NuGetForUnity/Editor/PackageSource/NugetPackageSourceV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ public List<INugetPackage> GetUpdates(
try
{
var newPackages = GetPackagesFromUrl(url);
CopyIsManuallyInstalled(newPackages, packagesCollection);
updates.AddRange(newPackages);
}
catch (Exception e)
Expand Down Expand Up @@ -522,5 +523,16 @@ private List<INugetPackage> GetUpdatesFallback(
NugetLogger.LogVerbose("NugetPackageSource.GetUpdatesFallback took {0} ms", stopwatch.ElapsedMilliseconds);
return updates;
}

private void CopyIsManuallyInstalled(List<INugetPackage> newPackages, ICollection<INugetPackage> packagesToUpdate)
{
foreach (var newPackage in newPackages)
{
newPackage.IsManuallyInstalled =
packagesToUpdate.FirstOrDefault(packageToUpdate => packageToUpdate.Id.Equals(newPackage.Id, StringComparison.OrdinalIgnoreCase))
?.IsManuallyInstalled ??
false;
}
}
}
}
12 changes: 12 additions & 0 deletions src/NuGetForUnity/Editor/PackageSource/NugetPackageSourceV3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ await ApiClient.SearchPackageAsync(
.GetAwaiter()
.GetResult();

CopyIsManuallyInstalled(packagesFromServer, packagesToFetch);
packagesFromServer.Sort();
return packagesFromServer;
}
Expand Down Expand Up @@ -313,5 +314,16 @@ private NugetApiClientV3 InitializeApiClient()
ApiClientCache.Add(SavedPath, apiClient);
return apiClient;
}

private void CopyIsManuallyInstalled(List<INugetPackage> newPackages, ICollection<INugetPackage> packagesToUpdate)
{
foreach (var newPackage in newPackages)
{
newPackage.IsManuallyInstalled =
packagesToUpdate.FirstOrDefault(packageToUpdate => packageToUpdate.Id.Equals(newPackage.Id, StringComparison.OrdinalIgnoreCase))
?.IsManuallyInstalled ??
false;
}
}
}
}
Loading

0 comments on commit 93784ca

Please sign in to comment.