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
6 changes: 3 additions & 3 deletions GVFS/GVFS.Common/Http/CacheServerResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ public bool TryResolveUrlFromRemote(
if (cacheServerName.Equals(CacheServerInfo.ReservedNames.Default, StringComparison.OrdinalIgnoreCase))
{
cacheServer =
serverGVFSConfig.CacheServers.FirstOrDefault(cache => cache.GlobalDefault)
serverGVFSConfig?.CacheServers.FirstOrDefault(cache => cache.GlobalDefault)
?? this.CreateNone();
}
else
{
cacheServer = serverGVFSConfig.CacheServers.FirstOrDefault(cache =>
cacheServer = serverGVFSConfig?.CacheServers.FirstOrDefault(cache =>
cache.Name.Equals(cacheServerName, StringComparison.OrdinalIgnoreCase));

if (cacheServer == null)
Expand Down Expand Up @@ -87,7 +87,7 @@ public CacheServerInfo ResolveNameFromRemote(
}

return
serverGVFSConfig.CacheServers.FirstOrDefault(cache => cache.Url.Equals(cacheServerUrl, StringComparison.OrdinalIgnoreCase))
serverGVFSConfig?.CacheServers.FirstOrDefault(cache => cache.Url.Equals(cacheServerUrl, StringComparison.OrdinalIgnoreCase))
?? new CacheServerInfo(cacheServerUrl, CacheServerInfo.ReservedNames.UserDefined);
}

Expand Down
59 changes: 40 additions & 19 deletions GVFS/GVFS/CommandLine/CacheServerVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,47 +48,68 @@ protected override void Execute(GVFSEnlistment enlistment)
this.ReportErrorAndExit(tracer, "Authentication failed: " + authErrorMessage);
}

ServerGVFSConfig serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);

CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);
ServerGVFSConfig serverGVFSConfig = null;
string error = null;

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

if (!cacheServerResolver.TrySaveUrlToLocalConfig(cacheServer, out error))
{
this.ReportErrorAndExit("Failed to save cache to config: " + error);
}

this.Output.WriteLine("You must remount GVFS for this to take effect.");
}
else if (this.ListCacheServers)
{
List<CacheServerInfo> cacheServers = serverGVFSConfig.CacheServers.ToList();

if (cacheServers != null && cacheServers.Any())
{
this.Output.WriteLine();
this.Output.WriteLine("Available cache servers for: " + enlistment.RepoUrl);
foreach (CacheServerInfo cacheServer in cacheServers)
foreach (CacheServerInfo cacheServerInfo in cacheServers)
{
this.Output.WriteLine(cacheServer);
this.Output.WriteLine(cacheServerInfo);
}
}
else
{
this.Output.WriteLine("There are no available cache servers for: " + enlistment.RepoUrl);
}
}
else if (this.CacheToSet != null)
{
// Setting a new cache server
CacheServerInfo cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheToSet);

// For set operation, allow fallback if config endpoint fails but cache server URL is valid
serverGVFSConfig = this.QueryGVFSConfigWithFallbackCacheServer(
tracer,
enlistment,
retryConfig,
cacheServer);

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

if (!cacheServerResolver.TrySaveUrlToLocalConfig(cacheServer, out error))
{
this.ReportErrorAndExit("Failed to save cache to config: " + error);
}

this.Output.WriteLine("You must remount GVFS for this to take effect.");
}
else
{
string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment);
CacheServerInfo cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerUrl, serverGVFSConfig);
// Default operation: get current cache server info
CacheServerInfo cacheServer = CacheServerResolver.GetCacheServerFromConfig(enlistment);

// For get operation, allow fallback if config endpoint fails but cache server URL is valid
serverGVFSConfig =this.QueryGVFSConfigWithFallbackCacheServer(
tracer,
enlistment,
retryConfig,
cacheServer);

CacheServerInfo resolvedCacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, serverGVFSConfig);

this.Output.WriteLine("Using cache server: " + cacheServer);
this.Output.WriteLine("Using cache server: " + resolvedCacheServer);
}
}
}
Expand Down
14 changes: 9 additions & 5 deletions GVFS/GVFS/CommandLine/CloneVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,12 @@ public override void Execute()
string resolvedLocalCacheRoot;
if (string.IsNullOrWhiteSpace(this.LocalCacheRoot))
{
string localCacheRootError;
if (!LocalCacheResolver.TryGetDefaultLocalCacheRoot(enlistment, out resolvedLocalCacheRoot, out localCacheRootError))
string localCacheRootError;
if (!LocalCacheResolver.TryGetDefaultLocalCacheRoot(enlistment, out resolvedLocalCacheRoot, out localCacheRootError))
{
this.ReportErrorAndExit(
tracer,
$"Failed to determine the default location for the local GVFS cache: `{localCacheRootError}`");
$"Failed to determine the default location for the local GVFS cache: `{localCacheRootError}`");
}
}
else
Expand All @@ -189,7 +189,12 @@ public override void Execute()
}

RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes));
serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);

serverGVFSConfig = this.QueryGVFSConfigWithFallbackCacheServer(
tracer,
enlistment,
retryConfig,
cacheServer);

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

Expand Down Expand Up @@ -237,7 +242,6 @@ public override void Execute()
exitCode = (int)result;
}
}

else
{
Process.Start(new ProcessStartInfo(
Expand Down
44 changes: 44 additions & 0 deletions GVFS/GVFS/CommandLine/GVFSVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,50 @@ protected RetryConfig GetRetryConfig(ITracer tracer, GVFSEnlistment enlistment,
return retryConfig;
}

/// <summary>
/// Attempts to query the GVFS config endpoint. If successful, returns the config.
/// If the query fails but a valid fallback cache server URL is available, returns null and continues.
/// (A warning will be logged later.)
/// If the query fails and no valid fallback is available, reports an error and exits.
/// </summary>
protected ServerGVFSConfig QueryGVFSConfigWithFallbackCacheServer(
ITracer tracer,
GVFSEnlistment enlistment,
RetryConfig retryConfig,
CacheServerInfo fallbackCacheServer)
{
ServerGVFSConfig serverGVFSConfig = null;
string errorMessage = null;
bool configSuccess = this.ShowStatusWhileRunning(
() =>
{
using (ConfigHttpRequestor configRequestor = new ConfigHttpRequestor(tracer, enlistment, retryConfig))
{
const bool LogErrors = true;
return configRequestor.TryQueryGVFSConfig(LogErrors, out serverGVFSConfig, out _, out errorMessage);
}
},
"Querying remote for config",
suppressGvfsLogMessage: true);

if (!configSuccess)
{
// If a valid cache server URL is available, warn and continue
if (fallbackCacheServer != null && !string.IsNullOrWhiteSpace(fallbackCacheServer.Url))
{
// Continue without config
// Warning will be logged/displayed when version check is run
return null;
}
else
{
this.ReportErrorAndExit(tracer, "Unable to query /gvfs/config" + Environment.NewLine + errorMessage);
}
}
return serverGVFSConfig;
}

// Restore original QueryGVFSConfig for other callers
protected ServerGVFSConfig QueryGVFSConfig(ITracer tracer, GVFSEnlistment enlistment, RetryConfig retryConfig)
{
ServerGVFSConfig serverGVFSConfig = null;
Expand Down
40 changes: 23 additions & 17 deletions GVFS/GVFS/CommandLine/MountVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ protected override void Execute(GVFSEnlistment enlistment)
this.ReportErrorAndExit("Error installing hooks: " + errorMessage);
}

CacheServerInfo cacheServer = this.ResolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment);
var resolvedCacheServer = this.ResolvedCacheServer;
var cacheServerFromConfig = resolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment);

tracer.AddLogFileEventListener(
GVFSEnlistment.GetNewGVFSLogFileName(enlistment.GVFSLogsRoot, GVFSConstants.LogFileTypes.MountVerb),
Expand All @@ -104,7 +105,7 @@ protected override void Execute(GVFSEnlistment enlistment)
tracer.WriteStartEvent(
enlistment.EnlistmentRoot,
enlistment.RepoUrl,
cacheServer.Url,
cacheServerFromConfig.Url,
new EventMetadata
{
{ "Unattended", this.Unattended },
Expand All @@ -122,7 +123,7 @@ protected override void Execute(GVFSEnlistment enlistment)
{
{ "KernelDriver.IsReady_Error", errorMessage },
{ TracingConstants.MessageKey.InfoMessage, "Service will retry" }
});
});

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

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

serverGVFSConfig = this.QueryGVFSConfig(tracer, enlistment, retryConfig);
serverGVFSConfig = this.QueryGVFSConfigWithFallbackCacheServer(
tracer,
enlistment,
retryConfig,
cacheServerFromConfig);
}

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

CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment);
cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, serverGVFSConfig);
this.Output.WriteLine("Configured cache server: " + cacheServer);
resolvedCacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerFromConfig.Url, serverGVFSConfig);
this.Output.WriteLine("Configured cache server: " + cacheServerFromConfig);
}

this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGVFSConfig, cacheServer);
this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGVFSConfig, resolvedCacheServer);

if (!this.ShowStatusWhileRunning(
() => { return this.PerformPreMountValidation(tracer, enlistment, out mountExecutableLocation, out errorMessage); },
Expand Down Expand Up @@ -193,23 +199,23 @@ protected override void Execute(GVFSEnlistment enlistment)
"Mounting"))
{
this.ReportErrorAndExit(tracer, errorMessage);
}

if (!this.Unattended)
}
if (!this.Unattended)
{
tracer.RelatedInfo($"{nameof(this.Execute)}: Registering for automount");

if (this.ShowStatusWhileRunning(
() => { return this.RegisterMount(enlistment, out errorMessage); },
"Registering for automount"))
if (this.ShowStatusWhileRunning(
() => { return this.RegisterMount(enlistment, out errorMessage); },
"Registering for automount"))
{
tracer.RelatedInfo($"{nameof(this.Execute)}: Registered for automount");
tracer.RelatedInfo($"{nameof(this.Execute)}: Registered for automount");
}
else
{
this.Output.WriteLine(" WARNING: " + errorMessage);
tracer.RelatedInfo($"{nameof(this.Execute)}: Failed to register for automount");
}
}
}
}
}
Expand Down
Loading
Loading