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
2 changes: 1 addition & 1 deletion GVFS/FastFetch/FastFetchLibGit2Repo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public FastFetchLibGit2Repo(ITracer tracer, string repoPath)
public virtual bool TryCopyBlobToFile(string sha, IEnumerable<PathWithMode> destinations, out long bytesWritten)
{
IntPtr objHandle;
if (Native.RevParseSingle(out objHandle, this.RepoHandle, sha) != Native.SuccessCode)
if (Native.RevParseSingle(out objHandle, this.RepoHandle, sha) != Native.ResultCode.Success)
{
bytesWritten = 0;
EventMetadata metadata = new EventMetadata();
Expand Down
26 changes: 0 additions & 26 deletions GVFS/GVFS.Common/Enlistment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,31 +109,5 @@ public virtual GitProcess CreateGitProcess()
{
return new GitProcess(this);
}

public bool GetTrustPackIndexesConfig()
{
var gitProcess = this.CreateGitProcess();
bool trustPackIndexes = true;
if (gitProcess.TryGetFromConfig(GVFSConstants.GitConfig.TrustPackIndexes, forceOutsideEnlistment: false, out var valueString)
&& bool.TryParse(valueString, out var trustPackIndexesConfig))
{
trustPackIndexes = trustPackIndexesConfig;
}

return trustPackIndexes;
}

public bool GetStatusHydrationConfig()
{
var gitProcess = this.CreateGitProcess();

if (gitProcess.TryGetFromConfig(GVFSConstants.GitConfig.ShowHydrationStatus, forceOutsideEnlistment: false, out var valueString)
&& bool.TryParse(valueString, out var statusHydrationConfig))
{
return statusHydrationConfig;
}

return GVFSConstants.GitConfig.ShowHydrationStatusDefault;
}
}
}
1 change: 1 addition & 0 deletions GVFS/GVFS.Common/GVFSConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public static class GitConfig
/* Intended to be a temporary config to allow testing of distrusting pack indexes from cache server
* before it is enabled by default. */
public const string TrustPackIndexes = GVFSPrefix + "trust-pack-indexes";
public const bool TrustPackIndexesDefault = true;

public const string ShowHydrationStatus = GVFSPrefix + "show-hydration-status";
public const bool ShowHydrationStatusDefault = false;
Expand Down
3 changes: 1 addition & 2 deletions GVFS/GVFS.Common/Git/GitObjects.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public virtual void DeleteTemporaryFiles()
}
}

public virtual bool TryDownloadPrefetchPacks(GitProcess gitProcess, long latestTimestamp, out List<string> packIndexes)
public virtual bool TryDownloadPrefetchPacks(GitProcess gitProcess, long latestTimestamp, bool trustPackIndexes, out List<string> packIndexes)
{
EventMetadata metadata = CreateEventMetadata();
metadata.Add("latestTimestamp", latestTimestamp);
Expand All @@ -166,7 +166,6 @@ public virtual bool TryDownloadPrefetchPacks(GitProcess gitProcess, long latestT
* pack file and an index file that do not match.
* Eventually we will make this the default, but it has a high performance cost for the first prefetch after
* cloning a large repository, so it must be explicitly enabled for now. */
bool trustPackIndexes = this.Enlistment.GetTrustPackIndexesConfig();
metadata.Add("trustPackIndexes", trustPackIndexes);

long requestId = HttpRequestor.GetNewRequestId();
Expand Down
5 changes: 5 additions & 0 deletions GVFS/GVFS.Common/Git/GitRepo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public GVFSLock GVFSLock
private set;
}

internal LibGit2RepoInvoker LibGit2RepoInvoker
{
get { return this.libgit2RepoInvoker; }
}

public void CloseActiveRepo()
{
this.libgit2RepoInvoker?.DisposeSharedRepo();
Expand Down
19 changes: 19 additions & 0 deletions GVFS/GVFS.Common/Git/LibGit2Exception.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GVFS.Common.Git
{
public class LibGit2Exception : Exception
{
public LibGit2Exception(string message) : base(message)
{
}

public LibGit2Exception(string message, Exception innerException) : base(message, innerException)
{
}
}
}
99 changes: 90 additions & 9 deletions GVFS/GVFS.Common/Git/LibGit2Repo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public LibGit2Repo(ITracer tracer, string repoPath)
Native.Init();

IntPtr repoHandle;
if (Native.Repo.Open(out repoHandle, repoPath) != Native.SuccessCode)
if (Native.Repo.Open(out repoHandle, repoPath) != Native.ResultCode.Success)
{
string reason = Native.GetLastError();
string message = "Couldn't open repo at " + repoPath + ": " + reason;
Expand Down Expand Up @@ -45,7 +45,7 @@ protected LibGit2Repo()
public Native.ObjectTypes? GetObjectType(string sha)
{
IntPtr objHandle;
if (Native.RevParseSingle(out objHandle, this.RepoHandle, sha) != Native.SuccessCode)
if (Native.RevParseSingle(out objHandle, this.RepoHandle, sha) != Native.ResultCode.Success)
{
return null;
}
Expand All @@ -63,7 +63,7 @@ protected LibGit2Repo()
public virtual string GetTreeSha(string commitish)
{
IntPtr objHandle;
if (Native.RevParseSingle(out objHandle, this.RepoHandle, commitish) != Native.SuccessCode)
if (Native.RevParseSingle(out objHandle, this.RepoHandle, commitish) != Native.ResultCode.Success)
{
return null;
}
Expand Down Expand Up @@ -99,7 +99,7 @@ public virtual bool CommitAndRootTreeExists(string commitish, out string treeSha
public virtual bool ObjectExists(string sha)
{
IntPtr objHandle;
if (Native.RevParseSingle(out objHandle, this.RepoHandle, sha) != Native.SuccessCode)
if (Native.RevParseSingle(out objHandle, this.RepoHandle, sha) != Native.ResultCode.Success)
{
return false;
}
Expand All @@ -111,7 +111,7 @@ public virtual bool ObjectExists(string sha)
public virtual bool TryCopyBlob(string sha, Action<Stream, long> writeAction)
{
IntPtr objHandle;
if (Native.RevParseSingle(out objHandle, this.RepoHandle, sha) != Native.SuccessCode)
if (Native.RevParseSingle(out objHandle, this.RepoHandle, sha) != Native.ResultCode.Success)
{
return false;
}
Expand Down Expand Up @@ -157,7 +157,7 @@ public virtual string[] GetMissingSubTrees(string treeSha)
{
List<string> missingSubtreesList = new List<string>();
IntPtr treeHandle;
if (Native.RevParseSingle(out treeHandle, this.RepoHandle, treeSha) != Native.SuccessCode
if (Native.RevParseSingle(out treeHandle, this.RepoHandle, treeSha) != Native.ResultCode.Success
|| treeHandle == IntPtr.Zero)
{
return Array.Empty<string>();
Expand Down Expand Up @@ -187,6 +187,68 @@ public virtual string[] GetMissingSubTrees(string treeSha)
return missingSubtreesList.ToArray();
}

/// <summary>
/// Get a config value from the repo's git config.
/// </summary>
/// <param name="name">Name of the config entry</param>
/// <returns>The config value, or null if not found.</returns>
public virtual string GetConfigString(string name)
{
IntPtr configHandle;
if (Native.Config.GetConfig(out configHandle, this.RepoHandle) != Native.ResultCode.Success)
{
throw new LibGit2Exception($"Failed to get config handle: {Native.GetLastError()}");
}
try
{
string value;
Native.ResultCode resultCode = Native.Config.GetString(out value, configHandle, name);
if (resultCode == Native.ResultCode.NotFound)
{
return null;
}
else if (resultCode != Native.ResultCode.Success)
{
throw new LibGit2Exception($"Failed to get config value for '{name}': {Native.GetLastError()}");
}

return value;
}
finally
{
Native.Config.Free(configHandle);
}
}

public virtual bool? GetConfigBool(string name)
{
IntPtr configHandle;
if (Native.Config.GetConfig(out configHandle, this.RepoHandle) != Native.ResultCode.Success)
{
throw new LibGit2Exception($"Failed to get config handle: {Native.GetLastError()}");
}
try
{
bool value;
Native.ResultCode resultCode = Native.Config.GetBool(out value, configHandle, name);
if (resultCode == Native.ResultCode.NotFound)
{
return null;
}
else if (resultCode != Native.ResultCode.Success)
{
throw new LibGit2Exception($"Failed to get config value for '{name}': {Native.GetLastError()}");
}

return value;
}
finally
{
Native.Config.Free(configHandle);
}

}

/// <summary>
/// Determine if the given index of a tree is a subtree and if it is missing.
/// If it is a missing subtree, return the SHA of the subtree.
Expand Down Expand Up @@ -242,7 +304,11 @@ protected virtual void Dispose(bool disposing)

public static class Native
{
public const uint SuccessCode = 0;
public enum ResultCode : int
{
Success = 0,
NotFound = -3,
}

public const string Git2NativeLibName = GVFSConstants.LibGit2LibraryName;

Expand All @@ -265,7 +331,7 @@ public static GitOid IntPtrToGitOid(IntPtr oidPtr)
public static extern int Shutdown();

[DllImport(Git2NativeLibName, EntryPoint = "git_revparse_single")]
public static extern uint RevParseSingle(out IntPtr objectHandle, IntPtr repoHandle, string oid);
public static extern ResultCode RevParseSingle(out IntPtr objectHandle, IntPtr repoHandle, string oid);

public static string GetLastError()
{
Expand Down Expand Up @@ -293,12 +359,27 @@ private struct GitError
public static class Repo
{
[DllImport(Git2NativeLibName, EntryPoint = "git_repository_open")]
public static extern uint Open(out IntPtr repoHandle, string path);
public static extern ResultCode Open(out IntPtr repoHandle, string path);

[DllImport(Git2NativeLibName, EntryPoint = "git_repository_free")]
public static extern void Free(IntPtr repoHandle);
}

public static class Config
{
[DllImport(Git2NativeLibName, EntryPoint = "git_repository_config")]
public static extern ResultCode GetConfig(out IntPtr configHandle, IntPtr repoHandle);

[DllImport(Git2NativeLibName, EntryPoint = "git_config_get_string")]
public static extern ResultCode GetString(out string value, IntPtr configHandle, string name);

[DllImport(Git2NativeLibName, EntryPoint = "git_config_get_bool")]
public static extern ResultCode GetBool(out bool value, IntPtr configHandle, string name);

[DllImport(Git2NativeLibName, EntryPoint = "git_config_free")]
public static extern void Free(IntPtr configHandle);
}

public static class Object
{
[DllImport(Git2NativeLibName, EntryPoint = "git_object_type")]
Expand Down
16 changes: 16 additions & 0 deletions GVFS/GVFS.Common/Git/LibGit2RepoInvoker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ public class LibGit2RepoInvoker : IDisposable
private volatile int activeCallers;
private LibGit2Repo sharedRepo;

public LibGit2RepoInvoker(ITracer tracer, string repoPath)
: this(tracer, () => new LibGit2Repo(tracer, repoPath))
{
}

public LibGit2RepoInvoker(ITracer tracer, Func<LibGit2Repo> createRepo)
{
this.tracer = tracer;
Expand Down Expand Up @@ -82,6 +87,17 @@ public void InitializeSharedRepo()
this.GetSharedRepo()?.ObjectExists("30380be3963a75e4a34e10726795d644659e1129");
}

public bool GetConfigBoolOrDefault(string key, bool defaultValue)
{
bool? value = defaultValue;
if (this.TryInvoke(repo => repo.GetConfigBool(key), out value))
{
return value ?? defaultValue;
}

return defaultValue;
}

private LibGit2Repo GetSharedRepo()
{
lock (this.sharedRepoLock)
Expand Down
3 changes: 2 additions & 1 deletion GVFS/GVFS.Common/GitStatusCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,8 @@ private void RebuildStatusCacheIfNeeded(bool ignoreBackoff)

private void UpdateHydrationSummary()
{
bool enabled = TEST_EnableHydrationSummaryOverride ?? this.context.Enlistment.GetStatusHydrationConfig();
bool enabled = TEST_EnableHydrationSummaryOverride
?? this.context.Repository.LibGit2RepoInvoker.GetConfigBoolOrDefault(GVFSConstants.GitConfig.ShowHydrationStatus, GVFSConstants.GitConfig.ShowHydrationStatusDefault);
if (!enabled)
{
return;
Expand Down
4 changes: 3 additions & 1 deletion GVFS/GVFS.Common/Maintenance/PrefetchStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ public bool TryPrefetchCommitsAndTrees(out string error, GitProcess gitProcess =
return false;
}

if (!this.GitObjects.TryDownloadPrefetchPacks(gitProcess, maxGoodTimeStamp, out packIndexes))
var trustPackIndexes = this.Context.Repository.LibGit2RepoInvoker.GetConfigBoolOrDefault(GVFSConstants.GitConfig.TrustPackIndexes, GVFSConstants.GitConfig.TrustPackIndexesDefault);

if (!this.GitObjects.TryDownloadPrefetchPacks(gitProcess, maxGoodTimeStamp, trustPackIndexes, out packIndexes))
{
error = "Failed to download prefetch packs";
return false;
Expand Down
Loading
Loading