Skip to content
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
93 changes: 62 additions & 31 deletions GVFS/GVFS.Common/Git/GitVersion.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
using System;
using System.Text;

namespace GVFS.Common.Git
{
public class GitVersion
{
public GitVersion(int major, int minor, int build, string platform = null, int revision = 0, int minorRevision = 0)
: this(major, minor, build, null, platform, revision, minorRevision) { }

public GitVersion(int major, int minor, int build, int? releaseCandidate = null, string platform = null, int revision = 0, int minorRevision = 0)
{
this.Major = major;
this.Minor = minor;
this.Build = build;
this.ReleaseCandidate = releaseCandidate;
this.Platform = platform;
this.Revision = revision;
this.MinorRevision = minorRevision;
Expand All @@ -18,6 +21,7 @@ public GitVersion(int major, int minor, int build, string platform = null, int r
public int Major { get; private set; }
public int Minor { get; private set; }
public int Build { get; private set; }
public int? ReleaseCandidate { get; private set; }
public string Platform { get; private set; }
public int Revision { get; private set; }
public int MinorRevision { get; private set; }
Expand All @@ -37,31 +41,12 @@ public static bool TryParseGitVersionCommandResult(string input, out GitVersion
return TryParseVersion(input, out version);
}

public static bool TryParseInstallerName(string input, string installerExtension, out GitVersion version)
{
// Installer name is of the form
// Git-2.14.1.gvfs.1.1.gb16030b-64-bit.exe

version = null;

if (!input.StartsWith("Git-", StringComparison.InvariantCultureIgnoreCase))
{
return false;
}

if (!input.EndsWith("-64-bit" + installerExtension, StringComparison.InvariantCultureIgnoreCase))
{
return false;
}

return TryParseVersion(input.Substring(4, input.Length - 15), out version);
}

public static bool TryParseVersion(string input, out GitVersion version)
{
version = null;

int major, minor, build, revision = 0, minorRevision = 0;
int? releaseCandidate = null;
string platform = null;

if (string.IsNullOrWhiteSpace(input))
Expand All @@ -73,10 +58,10 @@ public static bool TryParseVersion(string input, out GitVersion version)
int numComponents = parsedComponents.Length;

// We minimally accept the official Git version number format which
// consists of three components: "major.minor.build".
// consists of three components: "major.minor.build[.rcN]".
//
// The other supported formats are the Git for Windows and Microsoft Git
// formats which look like: "major.minor.build.platform.revision.minorRevision"
// formats which look like: "major.minor.build[.rcN].platform.revision.minorRevision"
// 0 1 2 3 4 5
// len 1 2 3 4 5 6
//
Expand All @@ -103,25 +88,54 @@ public static bool TryParseVersion(string input, out GitVersion version)
return false;
}

// Take the platform component verbatim
// Release candidate and/or platform
// Both of these are optional, but the release candidate is expected to be of the format 'rcN'
// where N is a number, helping us distinguish it from a platform string.
int platformIdx = 3;
if (numComponents >= 4)
{
platform = parsedComponents[3];
string tag = parsedComponents[3];

// Release candidate 'rcN'
if (tag.StartsWith("rc", StringComparison.OrdinalIgnoreCase) &&
tag.Length > 2 && int.TryParse(tag.Substring(2), out int rc) && rc >= 0)
{
releaseCandidate = rc;

// The next component will now be the (optional) platform.
// Subsequent components will be revision and minor revision so we need to adjust
// the platform index to account for the release candidate.
platformIdx = 4;
if (numComponents >= 5)
{
platform = parsedComponents[4];
}
}
else // Platform string only
{
platform = tag;
}
}

// Platform revision
if (numComponents < 5 || !TryParseComponent(parsedComponents[4], out revision))
if (numComponents > platformIdx + 1)
{
revision = 0;
if (!TryParseComponent(parsedComponents[platformIdx + 1], out revision))
{
revision = 0;
}
}

// Minor platform revision
if (numComponents < 6 || !TryParseComponent(parsedComponents[5], out minorRevision))
if (numComponents > platformIdx + 2)
{
minorRevision = 0;
if (!TryParseComponent(parsedComponents[platformIdx + 2], out minorRevision))
{
minorRevision = 0;
}
}

version = new GitVersion(major, minor, build, platform, revision, minorRevision);
version = new GitVersion(major, minor, build, releaseCandidate, platform, revision, minorRevision);
return true;
}

Expand All @@ -142,7 +156,12 @@ public bool IsLessThan(GitVersion other)

public override string ToString()
{
return string.Format("{0}.{1}.{2}.{3}.{4}.{5}", this.Major, this.Minor, this.Build, this.Platform, this.Revision, this.MinorRevision);
if (ReleaseCandidate is null)
{
return $"{Major}.{Minor}.{Build}.{Platform}.{Revision}.{MinorRevision}";
}

return $"{Major}.{Minor}.{Build}.rc{ReleaseCandidate}.{Platform}.{Revision}.{MinorRevision}";
}

private static bool TryParseComponent(string component, out int parsedComponent)
Expand Down Expand Up @@ -182,6 +201,18 @@ private int CompareVersionNumbers(GitVersion other)
return this.Build.CompareTo(other.Build);
}

if (this.ReleaseCandidate != other.ReleaseCandidate)
{
if (this.ReleaseCandidate.HasValue && other.ReleaseCandidate.HasValue)
{
return this.ReleaseCandidate.Value.CompareTo(other.ReleaseCandidate.Value);
}

// If one version has a release candidate and the other does not,
// the one without a release candidate is considered "greater than" the one with.
return other.ReleaseCandidate.HasValue ? 1 : -1;
}

if (this.Revision != other.Revision)
{
return this.Revision.CompareTo(other.Revision);
Expand Down
62 changes: 48 additions & 14 deletions GVFS/GVFS.UnitTests/Common/GitVersionTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using GVFS.Common;
using GVFS.Common.Git;
using GVFS.Common.Git;
using GVFS.Tests.Should;
using NUnit.Framework;

Expand All @@ -8,14 +7,6 @@ namespace GVFS.UnitTests.Common
[TestFixture]
public class GitVersionTests
{
[TestCase]
public void TryParseInstallerName()
{
this.ParseAndValidateInstallerVersion("Git-1.2.3.gvfs.4.5.gb16030b-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension);
this.ParseAndValidateInstallerVersion("git-1.2.3.gvfs.4.5.gb16030b-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension);
this.ParseAndValidateInstallerVersion("Git-1.2.3.gvfs.4.5.gb16030b-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension);
}

[TestCase]
public void Version_Data_Null_Returns_False()
{
Expand Down Expand Up @@ -118,6 +109,46 @@ public void Compare_Version_Minor_Greater()
version1.IsEqualTo(version2).ShouldEqual(false);
}

[TestCase]
public void Compare_ReleaseCandidate_Less()
{
GitVersion version1 = new GitVersion(1, 2, 3, 1, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, 2, "test", 4, 1);

version1.IsLessThan(version2).ShouldEqual(true);
version1.IsEqualTo(version2).ShouldEqual(false);
}

[TestCase]
public void Compare_ReleaseCandidate_Greater()
{
GitVersion version1 = new GitVersion(1, 2, 3, 2, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, 1, "test", 4, 1);

version1.IsLessThan(version2).ShouldEqual(false);
version1.IsEqualTo(version2).ShouldEqual(false);
}

[TestCase]
public void Compare_ReleaseCandidate_NonRC_Less()
{
GitVersion version1 = new GitVersion(1, 2, 3, 0, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, null, "test", 4, 1);

version1.IsLessThan(version2).ShouldEqual(true);
version1.IsEqualTo(version2).ShouldEqual(false);
}

[TestCase]
public void Compare_ReleaseCandidate_NonRC_Greater()
{
GitVersion version1 = new GitVersion(1, 2, 3, null, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, 0, "test", 4, 1);

version1.IsLessThan(version2).ShouldEqual(false);
version1.IsEqualTo(version2).ShouldEqual(false);
}

[TestCase]
public void Compare_Version_Build_Less()
{
Expand Down Expand Up @@ -187,6 +218,7 @@ public void Allow_Blank_Minor_Revision()
version.Major.ShouldEqual(1);
version.Minor.ShouldEqual(2);
version.Build.ShouldEqual(3);
version.ReleaseCandidate.ShouldEqual(null);
version.Platform.ShouldEqual("test");
version.Revision.ShouldEqual(4);
version.MinorRevision.ShouldEqual(0);
Expand All @@ -201,21 +233,23 @@ public void Allow_Invalid_Minor_Revision()
version.Major.ShouldEqual(1);
version.Minor.ShouldEqual(2);
version.Build.ShouldEqual(3);
version.ReleaseCandidate.ShouldEqual(null);
version.Platform.ShouldEqual("test");
version.Revision.ShouldEqual(4);
version.MinorRevision.ShouldEqual(0);
}

private void ParseAndValidateInstallerVersion(string installerName)
[TestCase]
public void Allow_ReleaseCandidates()
{
GitVersion version;
bool success = GitVersion.TryParseInstallerName(installerName, GVFSPlatform.Instance.Constants.InstallerExtension, out version);
success.ShouldBeTrue();
GitVersion.TryParseVersion("1.2.3.rc2.test.4.5", out version).ShouldEqual(true);

version.Major.ShouldEqual(1);
version.Minor.ShouldEqual(2);
version.Build.ShouldEqual(3);
version.Platform.ShouldEqual("gvfs");
version.ReleaseCandidate.ShouldEqual(2);
version.Platform.ShouldEqual("test");
version.Revision.ShouldEqual(4);
version.MinorRevision.ShouldEqual(5);
}
Expand Down
Loading