Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly order pre-release versions #610

Merged
merged 2 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading