Skip to content

Commit 6e7c9aa

Browse files
authored
Merge branch 'master' into async-prefetch-feedback
2 parents 29af4e4 + 864de47 commit 6e7c9aa

File tree

9 files changed

+183
-90
lines changed

9 files changed

+183
-90
lines changed

GVFS/GVFS.Common/Git/HashingStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public HashingStream(Stream stream)
1717
{
1818
this.stream = stream;
1919

20-
this.hash = SHA1.Create();
20+
this.hash = SHA1.Create(); // CodeQL [SM02196] SHA-1 is acceptable here because this is Git's hashing algorithm, not used for cryptographic purposes
2121
this.hashResult = null;
2222
this.hash.Initialize();
2323
this.closed = false;

GVFS/GVFS.Common/Http/CacheServerResolver.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@ public bool TryResolveUrlFromRemote(
5454
if (cacheServerName.Equals(CacheServerInfo.ReservedNames.Default, StringComparison.OrdinalIgnoreCase))
5555
{
5656
cacheServer =
57-
serverGVFSConfig.CacheServers.FirstOrDefault(cache => cache.GlobalDefault)
57+
serverGVFSConfig?.CacheServers.FirstOrDefault(cache => cache.GlobalDefault)
5858
?? this.CreateNone();
5959
}
6060
else
6161
{
62-
cacheServer = serverGVFSConfig.CacheServers.FirstOrDefault(cache =>
62+
cacheServer = serverGVFSConfig?.CacheServers.FirstOrDefault(cache =>
6363
cache.Name.Equals(cacheServerName, StringComparison.OrdinalIgnoreCase));
6464

6565
if (cacheServer == null)
@@ -87,7 +87,7 @@ public CacheServerInfo ResolveNameFromRemote(
8787
}
8888

8989
return
90-
serverGVFSConfig.CacheServers.FirstOrDefault(cache => cache.Url.Equals(cacheServerUrl, StringComparison.OrdinalIgnoreCase))
90+
serverGVFSConfig?.CacheServers.FirstOrDefault(cache => cache.Url.Equals(cacheServerUrl, StringComparison.OrdinalIgnoreCase))
9191
?? new CacheServerInfo(cacheServerUrl, CacheServerInfo.ReservedNames.UserDefined);
9292
}
9393

GVFS/GVFS.Common/SHA1Util.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static byte[] SHA1ForUTF8String(string s)
2121
{
2222
byte[] bytes = Encoding.UTF8.GetBytes(s);
2323

24-
using (SHA1 sha1 = SHA1.Create())
24+
using (SHA1 sha1 = SHA1.Create()) // CodeQL [SM02196] SHA-1 is acceptable here because this is Git's hashing algorithm, not used for cryptographic purposes
2525
{
2626
return sha1.ComputeHash(bytes);
2727
}

GVFS/GVFS.Virtualization/Projection/GitIndexProjection.FolderData.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void Include()
5454

5555
public string HashedChildrenNamesSha()
5656
{
57-
using (HashAlgorithm hash = SHA1.Create())
57+
using (HashAlgorithm hash = SHA1.Create()) // CodeQL [SM02196] SHA-1 is acceptable here because this is Git's hashing algorithm, not used for cryptographic purposes
5858
{
5959
for (int i = 0; i < this.ChildEntries.Count; i++)
6060
{

GVFS/GVFS/CommandLine/CacheServerVerb.cs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,47 +48,68 @@ protected override void Execute(GVFSEnlistment enlistment)
4848
this.ReportErrorAndExit(tracer, "Authentication failed: " + authErrorMessage);
4949
}
5050

51-
ServerGVFSConfig serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);
52-
5351
CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);
52+
ServerGVFSConfig serverGVFSConfig = null;
5453
string error = null;
5554

56-
if (this.CacheToSet != null)
55+
// Handle the three operation types: list, set, and get (default)
56+
if (this.ListCacheServers)
5757
{
58-
CacheServerInfo cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheToSet);
59-
cacheServer = this.ResolveCacheServer(tracer, cacheServer, cacheServerResolver, serverGVFSConfig);
58+
// For listing, require config endpoint to succeed
59+
serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);
6060

61-
if (!cacheServerResolver.TrySaveUrlToLocalConfig(cacheServer, out error))
62-
{
63-
this.ReportErrorAndExit("Failed to save cache to config: " + error);
64-
}
65-
66-
this.Output.WriteLine("You must remount GVFS for this to take effect.");
67-
}
68-
else if (this.ListCacheServers)
69-
{
7061
List<CacheServerInfo> cacheServers = serverGVFSConfig.CacheServers.ToList();
7162

7263
if (cacheServers != null && cacheServers.Any())
7364
{
7465
this.Output.WriteLine();
7566
this.Output.WriteLine("Available cache servers for: " + enlistment.RepoUrl);
76-
foreach (CacheServerInfo cacheServer in cacheServers)
67+
foreach (CacheServerInfo cacheServerInfo in cacheServers)
7768
{
78-
this.Output.WriteLine(cacheServer);
69+
this.Output.WriteLine(cacheServerInfo);
7970
}
8071
}
8172
else
8273
{
8374
this.Output.WriteLine("There are no available cache servers for: " + enlistment.RepoUrl);
8475
}
8576
}
77+
else if (this.CacheToSet != null)
78+
{
79+
// Setting a new cache server
80+
CacheServerInfo cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheToSet);
81+
82+
// For set operation, allow fallback if config endpoint fails but cache server URL is valid
83+
serverGVFSConfig = this.QueryGVFSConfigWithFallbackCacheServer(
84+
tracer,
85+
enlistment,
86+
retryConfig,
87+
cacheServer);
88+
89+
cacheServer = this.ResolveCacheServer(tracer, cacheServer, cacheServerResolver, serverGVFSConfig);
90+
91+
if (!cacheServerResolver.TrySaveUrlToLocalConfig(cacheServer, out error))
92+
{
93+
this.ReportErrorAndExit("Failed to save cache to config: " + error);
94+
}
95+
96+
this.Output.WriteLine("You must remount GVFS for this to take effect.");
97+
}
8698
else
8799
{
88-
string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment);
89-
CacheServerInfo cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerUrl, serverGVFSConfig);
100+
// Default operation: get current cache server info
101+
CacheServerInfo cacheServer = CacheServerResolver.GetCacheServerFromConfig(enlistment);
102+
103+
// For get operation, allow fallback if config endpoint fails but cache server URL is valid
104+
serverGVFSConfig =this.QueryGVFSConfigWithFallbackCacheServer(
105+
tracer,
106+
enlistment,
107+
retryConfig,
108+
cacheServer);
109+
110+
CacheServerInfo resolvedCacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, serverGVFSConfig);
90111

91-
this.Output.WriteLine("Using cache server: " + cacheServer);
112+
this.Output.WriteLine("Using cache server: " + resolvedCacheServer);
92113
}
93114
}
94115
}

GVFS/GVFS/CommandLine/CloneVerb.cs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using GVFS.Common.NamedPipes;
77
using GVFS.Common.Tracing;
88
using System;
9+
using System.ComponentModel;
910
using System.Diagnostics;
1011
using System.IO;
1112
using System.Linq;
@@ -163,12 +164,12 @@ public override void Execute()
163164
string resolvedLocalCacheRoot;
164165
if (string.IsNullOrWhiteSpace(this.LocalCacheRoot))
165166
{
166-
string localCacheRootError;
167-
if (!LocalCacheResolver.TryGetDefaultLocalCacheRoot(enlistment, out resolvedLocalCacheRoot, out localCacheRootError))
167+
string localCacheRootError;
168+
if (!LocalCacheResolver.TryGetDefaultLocalCacheRoot(enlistment, out resolvedLocalCacheRoot, out localCacheRootError))
168169
{
169170
this.ReportErrorAndExit(
170171
tracer,
171-
$"Failed to determine the default location for the local GVFS cache: `{localCacheRootError}`");
172+
$"Failed to determine the default location for the local GVFS cache: `{localCacheRootError}`");
172173
}
173174
}
174175
else
@@ -190,7 +191,12 @@ public override void Execute()
190191
}
191192

192193
RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes));
193-
serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);
194+
195+
serverGVFSConfig = this.QueryGVFSConfigWithFallbackCacheServer(
196+
tracer,
197+
enlistment,
198+
retryConfig,
199+
cacheServer);
194200

195201
cacheServer = this.ResolveCacheServer(tracer, cacheServer, cacheServerResolver, serverGVFSConfig);
196202

@@ -238,18 +244,26 @@ public override void Execute()
238244
exitCode = (int)result;
239245
}
240246
}
241-
242247
else
243248
{
244-
Process.Start(new ProcessStartInfo(
245-
fileName: Assembly.GetExecutingAssembly().Location,
246-
arguments: "prefetch --commits")
249+
try
247250
{
248-
UseShellExecute = true,
249-
WindowStyle = ProcessWindowStyle.Minimized,
250-
WorkingDirectory = enlistment.EnlistmentRoot
251-
});
252-
this.Output.WriteLine("\r\nPrefetch of commit graph has been started in another window. Git operations involving history may be slower until prefetch has completed.\r\n");
251+
string gvfsExecutable = Assembly.GetExecutingAssembly().Location;
252+
Process.Start(new ProcessStartInfo(
253+
fileName: gvfsExecutable,
254+
arguments: "prefetch --commits")
255+
{
256+
UseShellExecute = true,
257+
WindowStyle = ProcessWindowStyle.Minimized,
258+
WorkingDirectory = enlistment.EnlistmentRoot
259+
});
260+
this.Output.WriteLine("\r\nPrefetch of commit graph has been started as a background process. Git operations involving history may be slower until prefetch has completed.\r\n");
261+
}
262+
catch (Win32Exception ex)
263+
{
264+
this.Output.WriteLine("\r\nError starting prefetch: " + ex.Message);
265+
this.Output.WriteLine("Run 'gvfs prefetch --commits' from within your enlistment to prefetch the commit graph.");
266+
}
253267
}
254268
}
255269

GVFS/GVFS/CommandLine/GVFSVerb.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,50 @@ protected RetryConfig GetRetryConfig(ITracer tracer, GVFSEnlistment enlistment,
493493
return retryConfig;
494494
}
495495

496+
/// <summary>
497+
/// Attempts to query the GVFS config endpoint. If successful, returns the config.
498+
/// If the query fails but a valid fallback cache server URL is available, returns null and continues.
499+
/// (A warning will be logged later.)
500+
/// If the query fails and no valid fallback is available, reports an error and exits.
501+
/// </summary>
502+
protected ServerGVFSConfig QueryGVFSConfigWithFallbackCacheServer(
503+
ITracer tracer,
504+
GVFSEnlistment enlistment,
505+
RetryConfig retryConfig,
506+
CacheServerInfo fallbackCacheServer)
507+
{
508+
ServerGVFSConfig serverGVFSConfig = null;
509+
string errorMessage = null;
510+
bool configSuccess = this.ShowStatusWhileRunning(
511+
() =>
512+
{
513+
using (ConfigHttpRequestor configRequestor = new ConfigHttpRequestor(tracer, enlistment, retryConfig))
514+
{
515+
const bool LogErrors = true;
516+
return configRequestor.TryQueryGVFSConfig(LogErrors, out serverGVFSConfig, out _, out errorMessage);
517+
}
518+
},
519+
"Querying remote for config",
520+
suppressGvfsLogMessage: true);
521+
522+
if (!configSuccess)
523+
{
524+
// If a valid cache server URL is available, warn and continue
525+
if (fallbackCacheServer != null && !string.IsNullOrWhiteSpace(fallbackCacheServer.Url))
526+
{
527+
// Continue without config
528+
// Warning will be logged/displayed when version check is run
529+
return null;
530+
}
531+
else
532+
{
533+
this.ReportErrorAndExit(tracer, "Unable to query /gvfs/config" + Environment.NewLine + errorMessage);
534+
}
535+
}
536+
return serverGVFSConfig;
537+
}
538+
539+
// Restore original QueryGVFSConfig for other callers
496540
protected ServerGVFSConfig QueryGVFSConfig(ITracer tracer, GVFSEnlistment enlistment, RetryConfig retryConfig)
497541
{
498542
ServerGVFSConfig serverGVFSConfig = null;

GVFS/GVFS/CommandLine/MountVerb.cs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ protected override void Execute(GVFSEnlistment enlistment)
9595
this.ReportErrorAndExit("Error installing hooks: " + errorMessage);
9696
}
9797

98-
CacheServerInfo cacheServer = this.ResolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment);
98+
var resolvedCacheServer = this.ResolvedCacheServer;
99+
var cacheServerFromConfig = resolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment);
99100

100101
tracer.AddLogFileEventListener(
101102
GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.MountVerb),
@@ -104,7 +105,7 @@ protected override void Execute(GVFSEnlistment enlistment)
104105
tracer.WriteStartEvent(
105106
enlistment.EnlistmentRoot,
106107
enlistment.RepoUrl,
107-
cacheServer.Url,
108+
cacheServerFromConfig.Url,
108109
new EventMetadata
109110
{
110111
{ "Unattended", this.Unattended },
@@ -122,7 +123,7 @@ protected override void Execute(GVFSEnlistment enlistment)
122123
{
123124
{ "KernelDriver.IsReady_Error", errorMessage },
124125
{ TracingConstants.MessageKey.InfoMessage, "Service will retry" }
125-
});
126+
});
126127

127128
if (!this.ShowStatusWhileRunning(
128129
() => { return this.TryEnableAndAttachPrjFltThroughService(enlistment.EnlistmentRoot, out errorMessage); },
@@ -134,7 +135,8 @@ protected override void Execute(GVFSEnlistment enlistment)
134135

135136
RetryConfig retryConfig = null;
136137
ServerGVFSConfig serverGVFSConfig = this.DownloadedGVFSConfig;
137-
if (!this.SkipVersionCheck)
138+
/* If resolved cache server was passed in, we've already checked server config and version check in previous operation. */
139+
if (resolvedCacheServer == null)
138140
{
139141
string authErrorMessage;
140142
if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage))
@@ -150,17 +152,21 @@ protected override void Execute(GVFSEnlistment enlistment)
150152
retryConfig = this.GetRetryConfig(tracer, enlistment);
151153
}
152154

153-
serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);
155+
serverGVFSConfig = this.QueryGVFSConfigWithFallbackCacheServer(
156+
tracer,
157+
enlistment,
158+
retryConfig,
159+
cacheServerFromConfig);
154160
}
155161

156162
this.ValidateClientVersions(tracer, enlistment, serverGVFSConfig, showWarnings: true);
157163

158164
CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);
159-
cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, serverGVFSConfig);
160-
this.Output.WriteLine("Configured cache server: " + cacheServer);
165+
resolvedCacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerFromConfig.Url, serverGVFSConfig);
166+
this.Output.WriteLine("Configured cache server: " + cacheServerFromConfig);
161167
}
162168

163-
this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGVFSConfig, cacheServer);
169+
this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGVFSConfig, resolvedCacheServer);
164170

165171
if (!this.ShowStatusWhileRunning(
166172
() => { return this.PerformPreMountValidation(tracer, enlistment, out mountExecutableLocation, out errorMessage); },
@@ -193,23 +199,23 @@ protected override void Execute(GVFSEnlistment enlistment)
193199
"Mounting"))
194200
{
195201
this.ReportErrorAndExit(tracer, errorMessage);
196-
}
197-
198-
if (!this.Unattended)
202+
}
203+
204+
if (!this.Unattended)
199205
{
200206
tracer.RelatedInfo($"{nameof(this.Execute)}: Registering for automount");
201-
202-
if (this.ShowStatusWhileRunning(
203-
() => { return this.RegisterMount(enlistment, out errorMessage); },
204-
"Registering for automount"))
207+
208+
if (this.ShowStatusWhileRunning(
209+
() => { return this.RegisterMount(enlistment, out errorMessage); },
210+
"Registering for automount"))
205211
{
206-
tracer.RelatedInfo($"{nameof(this.Execute)}: Registered for automount");
212+
tracer.RelatedInfo($"{nameof(this.Execute)}: Registered for automount");
207213
}
208214
else
209215
{
210216
this.Output.WriteLine(" WARNING: " + errorMessage);
211217
tracer.RelatedInfo($"{nameof(this.Execute)}: Failed to register for automount");
212-
}
218+
}
213219
}
214220
}
215221
}

0 commit comments

Comments
 (0)