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

Enforce only a minimum Git version #1719

Merged
merged 3 commits into from
Feb 9, 2021
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
4 changes: 2 additions & 2 deletions GVFS/GVFS.Common/GVFSConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public static partial class GVFSConstants

public const string GVFSEtwProviderName = "Microsoft.Git.GVFS";
public const string WorkingDirectoryRootName = "src";
public const string UnattendedEnvironmentVariable = "GVFS_UNATTENDED";

public const string UnattendedEnvironmentVariable = "GVFS_UNATTENDED";
public const string DefaultGVFSCacheFolderName = ".gvfsCache";

public const string GitIsNotInstalledError = "Could not find git.exe. Ensure that Git is installed.";
Expand Down
43 changes: 32 additions & 11 deletions GVFS/GVFS.Common/Git/GitVersion.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System;
using System.Text;

namespace GVFS.Common.Git
{
public class GitVersion
{
public GitVersion(int major, int minor, int build, string platform, int revision, int minorRevision)
public GitVersion(int major, int minor, int build, string platform = null, int revision = 0, int minorRevision = 0)
{
this.Major = major;
this.Minor = minor;
Expand All @@ -16,8 +17,8 @@ public GitVersion(int major, int minor, int build, string platform, int revision

public int Major { get; private set; }
public int Minor { get; private set; }
public string Platform { get; private set; }
public int Build { get; private set; }
public string Platform { get; private set; }
public int Revision { get; private set; }
public int MinorRevision { get; private set; }

Expand Down Expand Up @@ -59,46 +60,66 @@ public static bool TryParseInstallerName(string input, string installerExtension
public static bool TryParseVersion(string input, out GitVersion version)
{
version = null;
int major, minor, build, revision, minorRevision;

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

if (string.IsNullOrWhiteSpace(input))
{
return false;
}

string[] parsedComponents = input.Split(new char[] { '.' });
int parsedComponentsLength = parsedComponents.Length;
if (parsedComponentsLength < 5)
string[] parsedComponents = input.Split('.');
int numComponents = parsedComponents.Length;

// We minimally accept the official Git version number format which
// consists of three components: "major.minor.build".
//
// The other supported formats are the Git for Windows and Microsoft Git
// formats which look like: "major.minor.build.platform.revision.minorRevision"
// 0 1 2 3 4 5
// len 1 2 3 4 5 6
//
if (numComponents < 3)
{
return false;
}

// Major version
if (!TryParseComponent(parsedComponents[0], out major))
{
return false;
}

// Minor version
if (!TryParseComponent(parsedComponents[1], out minor))
{
return false;
}

// Build number
if (!TryParseComponent(parsedComponents[2], out build))
{
return false;
}

if (!TryParseComponent(parsedComponents[4], out revision))
// Take the platform component verbatim
if (numComponents >= 4)
{
return false;
platform = parsedComponents[3];
}

if (parsedComponentsLength < 6 || !TryParseComponent(parsedComponents[5], out minorRevision))
// Platform revision
if (numComponents < 5 || !TryParseComponent(parsedComponents[4], out revision))
{
minorRevision = 0;
revision = 0;
}

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

version = new GitVersion(major, minor, build, platform, revision, minorRevision);
return true;
Expand Down
6 changes: 4 additions & 2 deletions GVFS/GVFS.UnitTests/Common/GitVersionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ public void Version_Data_Empty_Returns_False()
}

[TestCase]
public void Version_Data_Not_Enough_Numbers_Returns_False()
public void Version_Data_Not_Enough_Numbers_Sets_Zeroes()
{
GitVersion version;
bool success = GitVersion.TryParseVersion("2.0.1.test", out version);
success.ShouldEqual(false);
success.ShouldEqual(true);
version.Revision.ShouldEqual(0);
version.MinorRevision.ShouldEqual(0);
}

[TestCase]
Expand Down
172 changes: 82 additions & 90 deletions GVFS/GVFS/CommandLine/GVFSVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,60 +34,60 @@ public GVFSVerb(bool validateOrigin = true)
this.Unattended = GVFSEnlistment.IsUnattended(tracer: null);

this.InitializeDefaultParameterValues();
}

[Flags]
private enum GitCoreGVFSFlags
{
// GVFS_SKIP_SHA_ON_INDEX
// Disables the calculation of the sha when writing the index
SkipShaOnIndex = 1 << 0,

// GVFS_BLOCK_COMMANDS
// Blocks git commands that are not allowed in a GVFS/Scalar repo
BlockCommands = 1 << 1,

// GVFS_MISSING_OK
// Normally git write-tree ensures that the objects referenced by the
// directory exist in the object database.This option disables this check.
MissingOk = 1 << 2,

// GVFS_NO_DELETE_OUTSIDE_SPARSECHECKOUT
// When marking entries to remove from the index and the working
// directory this option will take into account what the
// skip-worktree bit was set to so that if the entry has the
// skip-worktree bit set it will not be removed from the working
// directory. This will allow virtualized working directories to
// detect the change to HEAD and use the new commit tree to show
// the files that are in the working directory.
NoDeleteOutsideSparseCheckout = 1 << 3,

// GVFS_FETCH_SKIP_REACHABILITY_AND_UPLOADPACK
// While performing a fetch with a virtual file system we know
// that there will be missing objects and we don't want to download
// them just because of the reachability of the commits. We also
// don't want to download a pack file with commits, trees, and blobs
// since these will be downloaded on demand. This flag will skip the
// checks on the reachability of objects during a fetch as well as
// the upload pack so that extraneous objects don't get downloaded.
FetchSkipReachabilityAndUploadPack = 1 << 4,

// 1 << 5 has been deprecated

// GVFS_BLOCK_FILTERS_AND_EOL_CONVERSIONS
// With a virtual file system we only know the file size before any
// CRLF or smudge/clean filters processing is done on the client.
// To prevent file corruption due to truncation or expansion with
// garbage at the end, these filters must not run when the file
// is first accessed and brought down to the client. Git.exe can't
// currently tell the first access vs subsequent accesses so this
// flag just blocks them from occurring at all.
BlockFiltersAndEolConversions = 1 << 6,

// GVFS_PREFETCH_DURING_FETCH
// While performing a `git fetch` command, use the gvfs-helper to
// perform a "prefetch" of commits and trees.
PrefetchDuringFetch = 1 << 7,
}
derrickstolee marked this conversation as resolved.
Show resolved Hide resolved
[Flags]
private enum GitCoreGVFSFlags
{
// GVFS_SKIP_SHA_ON_INDEX
// Disables the calculation of the sha when writing the index
SkipShaOnIndex = 1 << 0,
// GVFS_BLOCK_COMMANDS
// Blocks git commands that are not allowed in a GVFS/Scalar repo
BlockCommands = 1 << 1,
// GVFS_MISSING_OK
// Normally git write-tree ensures that the objects referenced by the
// directory exist in the object database.This option disables this check.
MissingOk = 1 << 2,
// GVFS_NO_DELETE_OUTSIDE_SPARSECHECKOUT
// When marking entries to remove from the index and the working
// directory this option will take into account what the
// skip-worktree bit was set to so that if the entry has the
// skip-worktree bit set it will not be removed from the working
// directory. This will allow virtualized working directories to
// detect the change to HEAD and use the new commit tree to show
// the files that are in the working directory.
NoDeleteOutsideSparseCheckout = 1 << 3,
// GVFS_FETCH_SKIP_REACHABILITY_AND_UPLOADPACK
// While performing a fetch with a virtual file system we know
// that there will be missing objects and we don't want to download
// them just because of the reachability of the commits. We also
// don't want to download a pack file with commits, trees, and blobs
// since these will be downloaded on demand. This flag will skip the
// checks on the reachability of objects during a fetch as well as
// the upload pack so that extraneous objects don't get downloaded.
FetchSkipReachabilityAndUploadPack = 1 << 4,
// 1 << 5 has been deprecated
// GVFS_BLOCK_FILTERS_AND_EOL_CONVERSIONS
// With a virtual file system we only know the file size before any
// CRLF or smudge/clean filters processing is done on the client.
// To prevent file corruption due to truncation or expansion with
// garbage at the end, these filters must not run when the file
// is first accessed and brought down to the client. Git.exe can't
// currently tell the first access vs subsequent accesses so this
// flag just blocks them from occurring at all.
BlockFiltersAndEolConversions = 1 << 6,
// GVFS_PREFETCH_DURING_FETCH
// While performing a `git fetch` command, use the gvfs-helper to
// perform a "prefetch" of commits and trees.
PrefetchDuringFetch = 1 << 7,
}

public abstract string EnlistmentRootPathParameter { get; set; }
Expand Down Expand Up @@ -143,8 +143,8 @@ public string InternalParameters
public string ServicePipeName
{
get
{
return GVFSPlatform.Instance.GetGVFSServiceNamedPipeName(this.ServiceName);
{
return GVFSPlatform.Instance.GetGVFSServiceNamedPipeName(this.ServiceName);
}
}

Expand All @@ -169,15 +169,15 @@ public static bool TrySetRequiredGitConfigSettings(Enlistment enlistment)
GVFSConstants.DotGVFS.GitStatusCache.CachePath);

gitStatusCachePath = Paths.ConvertPathToGitFormat(gitStatusCachePath);
}

string coreGVFSFlags = Convert.ToInt32(
GitCoreGVFSFlags.SkipShaOnIndex |
GitCoreGVFSFlags.BlockCommands |
GitCoreGVFSFlags.MissingOk |
GitCoreGVFSFlags.NoDeleteOutsideSparseCheckout |
GitCoreGVFSFlags.FetchSkipReachabilityAndUploadPack |
GitCoreGVFSFlags.BlockFiltersAndEolConversions)
}
string coreGVFSFlags = Convert.ToInt32(
GitCoreGVFSFlags.SkipShaOnIndex |
GitCoreGVFSFlags.BlockCommands |
GitCoreGVFSFlags.MissingOk |
GitCoreGVFSFlags.NoDeleteOutsideSparseCheckout |
GitCoreGVFSFlags.FetchSkipReachabilityAndUploadPack |
GitCoreGVFSFlags.BlockFiltersAndEolConversions)
.ToString();

// These settings are required for normal GVFS functionality.
Expand Down Expand Up @@ -423,8 +423,8 @@ protected bool ShowStatusWhileRunning(

protected bool TryAuthenticate(ITracer tracer, GVFSEnlistment enlistment, out string authErrorMessage)
{
string authError = null;

string authError = null;
bool result = this.ShowStatusWhileRunning(
() => enlistment.Authentication.TryInitialize(tracer, enlistment, out authError),
"Authenticating",
Expand Down Expand Up @@ -884,31 +884,23 @@ private void CheckGitVersion(ITracer tracer, GVFSEnlistment enlistment, out stri
this.ReportErrorAndExit(tracer, "Error: Invalid version of git {0}. Must use gvfs version.", version);
}

if (ProcessHelper.IsDevelopmentVersion())
if (gitVersion.IsLessThan(GVFSConstants.SupportedGitVersion))
{
if (gitVersion.IsLessThan(GVFSConstants.SupportedGitVersion))
{
this.ReportErrorAndExit(
tracer,
"Error: Installed git version {0} is less than the supported version of {1}.",
gitVersion,
GVFSConstants.SupportedGitVersion);
}
else if (!gitVersion.IsEqualTo(GVFSConstants.SupportedGitVersion))
{
this.Output.WriteLine($"Warning: Installed git version {gitVersion} does not match supported version of {GVFSConstants.SupportedGitVersion}.");
}
this.ReportErrorAndExit(
tracer,
"Error: Installed git version {0} is less than the supported version of {1}.",
gitVersion,
GVFSConstants.SupportedGitVersion);
}
else
else if (gitVersion.Revision != GVFSConstants.SupportedGitVersion.Revision)
derrickstolee marked this conversation as resolved.
Show resolved Hide resolved
{
if (!gitVersion.IsEqualTo(GVFSConstants.SupportedGitVersion))
{
this.ReportErrorAndExit(
tracer,
"Error: Installed git version {0} does not match supported version of {1}.",
gitVersion,
GVFSConstants.SupportedGitVersion);
}
this.ReportErrorAndExit(
tracer,
"Error: Installed git version {0} has revision number {1} instead of {2}." +
" This Git version is too new, so either downgrade Git or upgrade VFS for Git",
gitVersion,
gitVersion.Revision,
GVFSConstants.SupportedGitVersion.Revision);
}
}

Expand Down Expand Up @@ -1363,4 +1355,4 @@ public VerbAbortedException(GVFSVerb verb)
public GVFSVerb Verb { get; }
}
}
}
}