protected CacheServerInfo ResolveCacheServer( ITracer tracer, CacheServerInfo cacheServer, CacheServerResolver cacheServerResolver, ServerGSDConfig serverGSDConfig) { CacheServerInfo resolvedCacheServer = cacheServer; if (cacheServer.Url == null) { string cacheServerName = cacheServer.Name; string error = null; if (!cacheServerResolver.TryResolveUrlFromRemote( cacheServerName, serverGSDConfig, out resolvedCacheServer, out error)) { this.ReportErrorAndExit(tracer, error); } } else if (cacheServer.Name.Equals(CacheServerInfo.ReservedNames.UserDefined)) { resolvedCacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, serverGSDConfig); } this.Output.WriteLine("Using cache server: " + resolvedCacheServer); return(resolvedCacheServer); }
public bool TryResolveUrlFromRemote( string cacheServerName, ServerGSDConfig serverGSDConfig, out CacheServerInfo cacheServer, out string error) { if (string.IsNullOrWhiteSpace(cacheServerName)) { throw new InvalidOperationException("An empty name is not supported"); } cacheServer = null; error = null; if (cacheServerName.Equals(CacheServerInfo.ReservedNames.Default, StringComparison.OrdinalIgnoreCase)) { cacheServer = serverGSDConfig.CacheServers.FirstOrDefault(cache => cache.GlobalDefault) ?? this.CreateNone(); } else { cacheServer = serverGSDConfig.CacheServers.FirstOrDefault(cache => cache.Name.Equals(cacheServerName, StringComparison.OrdinalIgnoreCase)); if (cacheServer == null) { error = "No cache server found with name " + cacheServerName; return(false); } } return(true); }
protected override void Execute(GSDEnlistment enlistment) { this.BlockEmptyCacheServerUrl(this.CacheToSet); RetryConfig retryConfig = new RetryConfig(RetryConfig.DefaultMaxRetries, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); using (ITracer tracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "CacheVerb")) { string authErrorMessage; if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage)) { this.ReportErrorAndExit(tracer, "Authentication failed: " + authErrorMessage); } ServerGSDConfig serverGSDConfig = this.QueryGSDConfig(tracer, enlistment, retryConfig); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); string error = null; if (this.CacheToSet != null) { CacheServerInfo cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheToSet); cacheServer = this.ResolveCacheServer(tracer, cacheServer, cacheServerResolver, serverGSDConfig); if (!cacheServerResolver.TrySaveUrlToLocalConfig(cacheServer, out error)) { this.ReportErrorAndExit("Failed to save cache to config: " + error); } this.Output.WriteLine("You must remount GSD for this to take effect."); } else if (this.ListCacheServers) { List <CacheServerInfo> cacheServers = serverGSDConfig.CacheServers.ToList(); if (cacheServers != null && cacheServers.Any()) { this.Output.WriteLine(); this.Output.WriteLine("Available cache servers for: " + enlistment.RepoUrl); foreach (CacheServerInfo cacheServer in cacheServers) { this.Output.WriteLine(cacheServer); } } else { this.Output.WriteLine("There are no available cache servers for: " + enlistment.RepoUrl); } } else { string cacheServerUrl = CacheServerResolver.GetUrlFromConfig(enlistment); CacheServerInfo cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerUrl, serverGSDConfig); this.Output.WriteLine("Using cache server: " + cacheServer); } } }
private bool TryValidateGSDVersion(GSDEnlistment enlistment, ITracer tracer, ServerGSDConfig config, out string errorMessage, out bool errorIsFatal) { errorMessage = null; errorIsFatal = false; using (ITracer activity = tracer.StartActivity("ValidateGSDVersion", EventLevel.Informational)) { Version currentVersion = new Version(ProcessHelper.GetCurrentProcessVersion()); IEnumerable <ServerGSDConfig.VersionRange> allowedGvfsClientVersions = config != null ? config.AllowedGSDClientVersions : null; if (allowedGvfsClientVersions == null || !allowedGvfsClientVersions.Any()) { errorMessage = "WARNING: Unable to validate your GSD version" + Environment.NewLine; if (config == null) { errorMessage += "Could not query valid GSD versions from: " + Uri.EscapeUriString(enlistment.RepoUrl); } else { errorMessage += "Server not configured to provide supported GSD versions"; } return(false); } foreach (ServerGSDConfig.VersionRange versionRange in config.AllowedGSDClientVersions) { if (currentVersion >= versionRange.Min && (versionRange.Max == null || currentVersion <= versionRange.Max)) { activity.RelatedEvent( EventLevel.Informational, "GSDVersionValidated", new EventMetadata { { "SupportedVersionRange", versionRange }, }); enlistment.SetGSDVersion(currentVersion.ToString()); return(true); } } activity.RelatedError("GSD version {0} is not supported", currentVersion); } errorMessage = "ERROR: Your GSD version is no longer supported. Install the latest and try again."; errorIsFatal = true; return(false); }
public CacheServerInfo ResolveNameFromRemote( string cacheServerUrl, ServerGSDConfig serverGSDConfig) { if (string.IsNullOrWhiteSpace(cacheServerUrl)) { throw new InvalidOperationException("An empty url is not supported"); } if (this.InputMatchesEnlistmentUrl(cacheServerUrl)) { return(this.CreateNone()); } return (serverGSDConfig.CacheServers.FirstOrDefault(cache => cache.Url.Equals(cacheServerUrl, StringComparison.OrdinalIgnoreCase)) ?? new CacheServerInfo(cacheServerUrl, CacheServerInfo.ReservedNames.UserDefined)); }
private void InitializeServerConnection( ITracer tracer, GSDEnlistment enlistment, string cacheServerUrl, out GitObjectsHttpRequestor objectRequestor, out CacheServerInfo cacheServer) { RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); cacheServer = this.ResolvedCacheServer; ServerGSDConfig serverGSDConfig = this.ServerGSDConfig; if (!this.SkipVersionCheck) { string authErrorMessage; if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage)) { this.ReportErrorAndExit(tracer, "Unable to prefetch because authentication failed: " + authErrorMessage); } if (serverGSDConfig == null) { serverGSDConfig = this.QueryGSDConfig(tracer, enlistment, retryConfig); } if (cacheServer == null) { CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServerUrl, serverGSDConfig); } this.ValidateClientVersions(tracer, enlistment, serverGSDConfig, showWarnings: false); this.Output.WriteLine("Configured cache server: " + cacheServer); } this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGSDConfig, cacheServer); objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig); }
protected ServerGSDConfig QueryGSDConfig(ITracer tracer, GSDEnlistment enlistment, RetryConfig retryConfig) { ServerGSDConfig serverGSDConfig = null; string errorMessage = null; if (!this.ShowStatusWhileRunning( () => { using (ConfigHttpRequestor configRequestor = new ConfigHttpRequestor(tracer, enlistment, retryConfig)) { const bool LogErrors = true; return(configRequestor.TryQueryGSDConfig(LogErrors, out serverGSDConfig, out _, out errorMessage)); } }, "Querying remote for config", suppressGvfsLogMessage: true)) { this.ReportErrorAndExit(tracer, "Unable to query /gvfs/config" + Environment.NewLine + errorMessage); } return(serverGSDConfig); }
private bool TryDetermineLocalCacheAndInitializePaths( ITracer tracer, GSDEnlistment enlistment, ServerGSDConfig serverGSDConfig, CacheServerInfo currentCacheServer, string localCacheRoot, out string errorMessage) { errorMessage = null; LocalCacheResolver localCacheResolver = new LocalCacheResolver(enlistment); string error; string localCacheKey; if (!localCacheResolver.TryGetLocalCacheKeyFromLocalConfigOrRemoteCacheServers( tracer, serverGSDConfig, currentCacheServer, localCacheRoot, localCacheKey: out localCacheKey, errorMessage: out error)) { errorMessage = "Error determining local cache key: " + error; return(false); } EventMetadata metadata = new EventMetadata(); metadata.Add("localCacheRoot", localCacheRoot); metadata.Add("localCacheKey", localCacheKey); metadata.Add(TracingConstants.MessageKey.InfoMessage, "Initializing cache paths"); tracer.RelatedEvent(EventLevel.Informational, "CloneVerb_TryDetermineLocalCacheAndInitializePaths", metadata); enlistment.InitializeCachePathsFromKey(localCacheRoot, localCacheKey); return(true); }
protected void InitializeLocalCacheAndObjectsPaths( ITracer tracer, GSDEnlistment enlistment, RetryConfig retryConfig, ServerGSDConfig serverGSDConfig, CacheServerInfo cacheServer) { string error; if (!RepoMetadata.TryInitialize(tracer, Path.Combine(enlistment.EnlistmentRoot, GSDPlatform.Instance.Constants.DotGSDRoot), out error)) { this.ReportErrorAndExit(tracer, "Failed to initialize repo metadata: " + error); } this.InitializeCachePathsFromRepoMetadata(tracer, enlistment); // Note: Repos cloned with a version of GSD that predates the local cache will not have a local cache configured if (!string.IsNullOrWhiteSpace(enlistment.LocalCacheRoot)) { this.EnsureLocalCacheIsHealthy(tracer, enlistment, retryConfig, serverGSDConfig, cacheServer); } RepoMetadata.Shutdown(); }
protected override void Execute(GSDEnlistment enlistment) { string errorMessage = null; string mountExecutableLocation = null; using (JsonTracer tracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "ExecuteMount")) { PhysicalFileSystem fileSystem = new PhysicalFileSystem(); GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem); GSDContext context = new GSDContext(tracer, fileSystem, gitRepo, enlistment); if (!HooksInstaller.InstallHooks(context, out errorMessage)) { this.ReportErrorAndExit("Error installing hooks: " + errorMessage); } CacheServerInfo cacheServer = this.ResolvedCacheServer ?? CacheServerResolver.GetCacheServerFromConfig(enlistment); tracer.AddLogFileEventListener( GSDEnlistment.GetNewGSDLogFileName(enlistment.GSDLogsRoot, GSDConstants.LogFileTypes.MountVerb), EventLevel.Verbose, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, cacheServer.Url, new EventMetadata { { "Unattended", this.Unattended }, { "IsElevated", GSDPlatform.Instance.IsElevated() }, { "NamedPipeName", enlistment.NamedPipeName }, { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter }, }); RetryConfig retryConfig = null; ServerGSDConfig serverGSDConfig = this.DownloadedGSDConfig; if (!this.SkipVersionCheck) { string authErrorMessage; if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage)) { this.Output.WriteLine(" WARNING: " + authErrorMessage); this.Output.WriteLine(" Mount will proceed, but new files cannot be accessed until GSD can authenticate."); } if (serverGSDConfig == null) { if (retryConfig == null) { retryConfig = this.GetRetryConfig(tracer, enlistment); } serverGSDConfig = this.QueryGSDConfig(tracer, enlistment, retryConfig); } this.ValidateClientVersions(tracer, enlistment, serverGSDConfig, showWarnings: true); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ResolveNameFromRemote(cacheServer.Url, serverGSDConfig); this.Output.WriteLine("Configured cache server: " + cacheServer); } this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverGSDConfig, cacheServer); if (!this.ShowStatusWhileRunning( () => { return(this.PerformPreMountValidation(tracer, enlistment, out mountExecutableLocation, out errorMessage)); }, "Validating repo")) { this.ReportErrorAndExit(tracer, errorMessage); } if (!this.SkipVersionCheck) { string error; if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGSDRoot, out error)) { this.ReportErrorAndExit(tracer, error); } try { GitProcess git = new GitProcess(enlistment); this.LogEnlistmentInfoAndSetConfigValues(tracer, git, enlistment); } finally { RepoMetadata.Shutdown(); } } if (!this.ShowStatusWhileRunning( () => { return(this.TryMount(tracer, enlistment, mountExecutableLocation, out errorMessage)); }, "Mounting")) { this.ReportErrorAndExit(tracer, errorMessage); } if (!this.Unattended) { tracer.RelatedInfo($"{nameof(this.Execute)}: Registering for automount"); if (this.ShowStatusWhileRunning( () => { return(this.RegisterMount(enlistment, out errorMessage)); }, "Registering 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"); } } } }
public override void Execute() { int exitCode = 0; this.ValidatePathParameter(this.EnlistmentRootPathParameter); this.ValidatePathParameter(this.LocalCacheRoot); string fullEnlistmentRootPathParameter; string normalizedEnlistmentRootPath = this.GetCloneRoot(out fullEnlistmentRootPathParameter); if (!string.IsNullOrWhiteSpace(this.LocalCacheRoot)) { string fullLocalCacheRootPath = Path.GetFullPath(this.LocalCacheRoot); string errorMessage; string normalizedLocalCacheRootPath; if (!GSDPlatform.Instance.FileSystem.TryGetNormalizedPath(fullLocalCacheRootPath, out normalizedLocalCacheRootPath, out errorMessage)) { this.ReportErrorAndExit($"Failed to determine normalized path for '--local-cache-path' path {fullLocalCacheRootPath}: {errorMessage}"); } if (normalizedLocalCacheRootPath.StartsWith( Path.Combine(normalizedEnlistmentRootPath, GSDConstants.WorkingDirectoryRootName), StringComparison.OrdinalIgnoreCase)) { this.ReportErrorAndExit("'--local-cache-path' cannot be inside the src folder"); } } this.CheckNotInsideExistingRepo(normalizedEnlistmentRootPath); this.BlockEmptyCacheServerUrl(this.CacheServerUrl); try { GSDEnlistment enlistment; Result cloneResult = new Result(false); CacheServerInfo cacheServer = null; ServerGSDConfig serverGSDConfig = null; using (JsonTracer tracer = new JsonTracer(GSDConstants.GSDEtwProviderName, "GSDClone")) { cloneResult = this.TryCreateEnlistment(fullEnlistmentRootPathParameter, normalizedEnlistmentRootPath, out enlistment); if (cloneResult.Success) { tracer.AddLogFileEventListener( GSDEnlistment.GetNewGSDLogFileName(enlistment.GSDLogsRoot, GSDConstants.LogFileTypes.Clone), EventLevel.Informational, Keywords.Any); tracer.WriteStartEvent( enlistment.EnlistmentRoot, enlistment.RepoUrl, this.CacheServerUrl, new EventMetadata { { "Branch", this.Branch }, { "LocalCacheRoot", this.LocalCacheRoot }, { "SingleBranch", this.SingleBranch }, { "NoMount", this.NoMount }, { "NoPrefetch", this.NoPrefetch }, { "Unattended", this.Unattended }, { "IsElevated", GSDPlatform.Instance.IsElevated() }, { "NamedPipeName", enlistment.NamedPipeName }, { "ProcessID", Process.GetCurrentProcess().Id }, { nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter }, { nameof(fullEnlistmentRootPathParameter), fullEnlistmentRootPathParameter }, }); CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); cacheServer = cacheServerResolver.ParseUrlOrFriendlyName(this.CacheServerUrl); string resolvedLocalCacheRoot; if (string.IsNullOrWhiteSpace(this.LocalCacheRoot)) { string localCacheRootError; if (!LocalCacheResolver.TryGetDefaultLocalCacheRoot(enlistment, out resolvedLocalCacheRoot, out localCacheRootError)) { this.ReportErrorAndExit( tracer, $"Failed to determine the default location for the local GSD cache: `{localCacheRootError}`"); } } else { resolvedLocalCacheRoot = Path.GetFullPath(this.LocalCacheRoot); } this.Output.WriteLine("Clone parameters:"); this.Output.WriteLine(" Repo URL: " + enlistment.RepoUrl); this.Output.WriteLine(" Branch: " + (string.IsNullOrWhiteSpace(this.Branch) ? "Default" : this.Branch)); this.Output.WriteLine(" Cache Server: " + cacheServer); this.Output.WriteLine(" Local Cache: " + resolvedLocalCacheRoot); this.Output.WriteLine(" Destination: " + enlistment.EnlistmentRoot); string authErrorMessage; if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage)) { this.ReportErrorAndExit(tracer, "Cannot clone because authentication failed: " + authErrorMessage); } RetryConfig retryConfig = this.GetRetryConfig(tracer, enlistment, TimeSpan.FromMinutes(RetryConfig.FetchAndCloneTimeoutMinutes)); serverGSDConfig = this.QueryGSDConfig(tracer, enlistment, retryConfig); cacheServer = this.ResolveCacheServer(tracer, cacheServer, cacheServerResolver, serverGSDConfig); this.ValidateClientVersions(tracer, enlistment, serverGSDConfig, showWarnings: true); this.ShowStatusWhileRunning( () => { cloneResult = this.TryClone(tracer, enlistment, cacheServer, retryConfig, serverGSDConfig, resolvedLocalCacheRoot); return(cloneResult.Success); }, "Cloning", normalizedEnlistmentRootPath); } if (!cloneResult.Success) { tracer.RelatedError(cloneResult.ErrorMessage); } } if (cloneResult.Success) { if (!this.NoPrefetch) { ReturnCode result = this.Execute <PrefetchVerb>( enlistment, verb => { verb.Commits = true; verb.SkipVersionCheck = true; verb.ResolvedCacheServer = cacheServer; verb.ServerGSDConfig = serverGSDConfig; }); if (result != ReturnCode.Success) { this.Output.WriteLine("\r\nError during prefetch @ {0}", fullEnlistmentRootPathParameter); exitCode = (int)result; } } if (this.NoMount) { this.Output.WriteLine("\r\nIn order to mount, first cd to within your enlistment, then call: "); this.Output.WriteLine("gvfs mount"); } else { this.Execute <MountVerb>( enlistment, verb => { verb.SkipMountedCheck = true; verb.SkipVersionCheck = true; verb.ResolvedCacheServer = cacheServer; verb.DownloadedGSDConfig = serverGSDConfig; }); GitProcess git = new GitProcess(enlistment); git.ForceCheckoutAllFiles(); } } else { this.Output.WriteLine("\r\nCannot clone @ {0}", fullEnlistmentRootPathParameter); this.Output.WriteLine("Error: {0}", cloneResult.ErrorMessage); exitCode = (int)ReturnCode.GenericError; } } catch (AggregateException e) { this.Output.WriteLine("Cannot clone @ {0}:", fullEnlistmentRootPathParameter); foreach (Exception ex in e.Flatten().InnerExceptions) { this.Output.WriteLine("Exception: {0}", ex.ToString()); } exitCode = (int)ReturnCode.GenericError; } catch (VerbAbortedException) { throw; } catch (Exception e) { this.ReportErrorAndExit("Cannot clone @ {0}: {1}", fullEnlistmentRootPathParameter, e.ToString()); } Environment.Exit(exitCode); }
private Result TryClone( JsonTracer tracer, GSDEnlistment enlistment, CacheServerInfo cacheServer, RetryConfig retryConfig, ServerGSDConfig serverGSDConfig, string resolvedLocalCacheRoot) { Result pipeResult; using (NamedPipeServer pipeServer = this.StartNamedPipe(tracer, enlistment, out pipeResult)) { if (!pipeResult.Success) { return(pipeResult); } using (GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig)) { GitRefs refs = objectRequestor.QueryInfoRefs(this.SingleBranch ? this.Branch : null); if (refs == null) { return(new Result("Could not query info/refs from: " + Uri.EscapeUriString(enlistment.RepoUrl))); } if (this.Branch == null) { this.Branch = refs.GetDefaultBranch(); EventMetadata metadata = new EventMetadata(); metadata.Add("Branch", this.Branch); tracer.RelatedEvent(EventLevel.Informational, "CloneDefaultRemoteBranch", metadata); } else { if (!refs.HasBranch(this.Branch)) { EventMetadata metadata = new EventMetadata(); metadata.Add("Branch", this.Branch); tracer.RelatedEvent(EventLevel.Warning, "CloneBranchDoesNotExist", metadata); string errorMessage = string.Format("Remote branch {0} not found in upstream origin", this.Branch); return(new Result(errorMessage)); } } if (!enlistment.TryCreateEnlistmentFolders()) { string error = "Could not create enlistment directory"; tracer.RelatedError(error); return(new Result(error)); } string localCacheError; if (!this.TryDetermineLocalCacheAndInitializePaths(tracer, enlistment, serverGSDConfig, cacheServer, resolvedLocalCacheRoot, out localCacheError)) { tracer.RelatedError(localCacheError); return(new Result(localCacheError)); } Directory.CreateDirectory(enlistment.GitObjectsRoot); Directory.CreateDirectory(enlistment.GitPackRoot); Directory.CreateDirectory(enlistment.BlobSizesRoot); return(this.CreateClone(tracer, enlistment, objectRequestor, refs, this.Branch)); } } }
private void EnsureLocalCacheIsHealthy( ITracer tracer, GSDEnlistment enlistment, RetryConfig retryConfig, ServerGSDConfig serverGSDConfig, CacheServerInfo cacheServer) { if (!Directory.Exists(enlistment.LocalCacheRoot)) { try { tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Local cache root: {enlistment.LocalCacheRoot} missing, recreating it"); Directory.CreateDirectory(enlistment.LocalCacheRoot); } catch (Exception e) { EventMetadata metadata = new EventMetadata(); metadata.Add("Exception", e.ToString()); metadata.Add("enlistment.LocalCacheRoot", enlistment.LocalCacheRoot); tracer.RelatedError(metadata, $"{nameof(this.EnsureLocalCacheIsHealthy)}: Exception while trying to create local cache root"); this.ReportErrorAndExit(tracer, "Failed to create local cache: " + enlistment.LocalCacheRoot); } } // Validate that the GitObjectsRoot directory is on disk, and that the GSD repo is configured to use it. // If the directory is missing (and cannot be found in the mapping file) a new key for the repo will be added // to the mapping file and used for BOTH the GitObjectsRoot and BlobSizesRoot PhysicalFileSystem fileSystem = new PhysicalFileSystem(); if (Directory.Exists(enlistment.GitObjectsRoot)) { bool gitObjectsRootInAlternates = false; string alternatesFilePath = this.GetAlternatesPath(enlistment); if (File.Exists(alternatesFilePath)) { try { using (Stream stream = fileSystem.OpenFileStream( alternatesFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, callFlushFileBuffers: false)) { using (StreamReader reader = new StreamReader(stream)) { while (!reader.EndOfStream) { string alternatesLine = reader.ReadLine(); if (string.Equals(alternatesLine, enlistment.GitObjectsRoot, StringComparison.OrdinalIgnoreCase)) { gitObjectsRootInAlternates = true; } } } } } catch (Exception e) { EventMetadata exceptionMetadata = new EventMetadata(); exceptionMetadata.Add("Exception", e.ToString()); tracer.RelatedError(exceptionMetadata, $"{nameof(this.EnsureLocalCacheIsHealthy)}: Exception while trying to validate alternates file"); this.ReportErrorAndExit(tracer, $"Failed to validate that alternates file includes git objects root: {e.Message}"); } } else { tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Alternates file not found"); } if (!gitObjectsRootInAlternates) { tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: GitObjectsRoot ({enlistment.GitObjectsRoot}) missing from alternates files, recreating alternates"); string error; if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out error)) { this.ReportErrorAndExit(tracer, $"Failed to update alternates file to include git objects root: {error}"); } } } else { tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: GitObjectsRoot ({enlistment.GitObjectsRoot}) missing, determining new root"); if (cacheServer == null) { cacheServer = CacheServerResolver.GetCacheServerFromConfig(enlistment); } string error; if (serverGSDConfig == null) { if (retryConfig == null) { if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error)) { this.ReportErrorAndExit(tracer, "Failed to determine GSD timeout and max retries: " + error); } } serverGSDConfig = this.QueryGSDConfig(tracer, enlistment, retryConfig); } string localCacheKey; LocalCacheResolver localCacheResolver = new LocalCacheResolver(enlistment); if (!localCacheResolver.TryGetLocalCacheKeyFromLocalConfigOrRemoteCacheServers( tracer, serverGSDConfig, cacheServer, enlistment.LocalCacheRoot, localCacheKey: out localCacheKey, errorMessage: out error)) { this.ReportErrorAndExit(tracer, $"Previous git objects root ({enlistment.GitObjectsRoot}) not found, and failed to determine new local cache key: {error}"); } EventMetadata metadata = new EventMetadata(); metadata.Add("localCacheRoot", enlistment.LocalCacheRoot); metadata.Add("localCacheKey", localCacheKey); metadata.Add(TracingConstants.MessageKey.InfoMessage, "Initializing and persisting updated paths"); tracer.RelatedEvent(EventLevel.Informational, "GSDVerb_EnsureLocalCacheIsHealthy_InitializePathsFromKey", metadata); enlistment.InitializeCachePathsFromKey(enlistment.LocalCacheRoot, localCacheKey); tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Creating GitObjectsRoot ({enlistment.GitObjectsRoot}), GitPackRoot ({enlistment.GitPackRoot}), and BlobSizesRoot ({enlistment.BlobSizesRoot})"); try { Directory.CreateDirectory(enlistment.GitObjectsRoot); Directory.CreateDirectory(enlistment.GitPackRoot); } catch (Exception e) { EventMetadata exceptionMetadata = new EventMetadata(); exceptionMetadata.Add("Exception", e.ToString()); exceptionMetadata.Add("enlistment.LocalCacheRoot", enlistment.LocalCacheRoot); exceptionMetadata.Add("enlistment.GitObjectsRoot", enlistment.GitObjectsRoot); exceptionMetadata.Add("enlistment.GitPackRoot", enlistment.GitPackRoot); exceptionMetadata.Add("enlistment.BlobSizesRoot", enlistment.BlobSizesRoot); tracer.RelatedError(exceptionMetadata, $"{nameof(this.InitializeLocalCacheAndObjectsPaths)}: Exception while trying to create objects, pack, and sizes folders"); this.ReportErrorAndExit(tracer, "Failed to create objects, pack, and sizes folders"); } tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Creating new alternates file"); if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out error)) { this.ReportErrorAndExit(tracer, $"Failed to update alterates file with new objects path: {error}"); } tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Saving git objects root ({enlistment.GitObjectsRoot}) in repo metadata"); RepoMetadata.Instance.SetGitObjectsRoot(enlistment.GitObjectsRoot); tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: Saving blob sizes root ({enlistment.BlobSizesRoot}) in repo metadata"); RepoMetadata.Instance.SetBlobSizesRoot(enlistment.BlobSizesRoot); } // Validate that the BlobSizesRoot folder is on disk. // Note that if a user performed an action that resulted in the entire .gvfscache being deleted, the code above // for validating GitObjectsRoot will have already taken care of generating a new key and setting a new enlistment.BlobSizesRoot path if (!Directory.Exists(enlistment.BlobSizesRoot)) { tracer.RelatedInfo($"{nameof(this.EnsureLocalCacheIsHealthy)}: BlobSizesRoot ({enlistment.BlobSizesRoot}) not found, re-creating"); try { Directory.CreateDirectory(enlistment.BlobSizesRoot); } catch (Exception e) { EventMetadata exceptionMetadata = new EventMetadata(); exceptionMetadata.Add("Exception", e.ToString()); exceptionMetadata.Add("enlistment.BlobSizesRoot", enlistment.BlobSizesRoot); tracer.RelatedError(exceptionMetadata, $"{nameof(this.InitializeLocalCacheAndObjectsPaths)}: Exception while trying to create blob sizes folder"); this.ReportErrorAndExit(tracer, "Failed to create blob sizes folder"); } } }
protected void ValidateClientVersions(ITracer tracer, GSDEnlistment enlistment, ServerGSDConfig gvfsConfig, bool showWarnings) { this.CheckGitVersion(tracer, enlistment, out string gitVersion); enlistment.SetGitVersion(gitVersion); this.GetGSDHooksPathAndCheckVersion(tracer, out string hooksVersion); enlistment.SetGSDHooksVersion(hooksVersion); string errorMessage = null; bool errorIsFatal = false; if (!this.TryValidateGSDVersion(enlistment, tracer, gvfsConfig, out errorMessage, out errorIsFatal)) { if (errorIsFatal) { this.ReportErrorAndExit(tracer, errorMessage); } else if (showWarnings) { this.Output.WriteLine(); this.Output.WriteLine(errorMessage); this.Output.WriteLine(); } } }
public bool TryQueryGSDConfig(bool logErrors, out ServerGSDConfig serverGSDConfig, out HttpStatusCode?httpStatus, out string errorMessage) { serverGSDConfig = null; httpStatus = null; errorMessage = null; Uri gvfsConfigEndpoint; string gvfsConfigEndpointString = this.repoUrl + GSDConstants.Endpoints.GSDConfig; try { gvfsConfigEndpoint = new Uri(gvfsConfigEndpointString); } catch (UriFormatException e) { EventMetadata metadata = new EventMetadata(); metadata.Add("Method", nameof(this.TryQueryGSDConfig)); metadata.Add("Exception", e.ToString()); metadata.Add("Url", gvfsConfigEndpointString); this.Tracer.RelatedError(metadata, "UriFormatException when constructing Uri", Keywords.Network); return(false); } long requestId = HttpRequestor.GetNewRequestId(); RetryWrapper <ServerGSDConfig> retrier = new RetryWrapper <ServerGSDConfig>(this.RetryConfig.MaxAttempts, CancellationToken.None); if (logErrors) { retrier.OnFailure += RetryWrapper <ServerGSDConfig> .StandardErrorHandler(this.Tracer, requestId, "QueryGvfsConfig"); } RetryWrapper <ServerGSDConfig> .InvocationResult output = retrier.Invoke( tryCount => { using (GitEndPointResponseData response = this.SendRequest( requestId, gvfsConfigEndpoint, HttpMethod.Get, requestContent: null, cancellationToken: CancellationToken.None)) { if (response.HasErrors) { return(new RetryWrapper <ServerGSDConfig> .CallbackResult(response.Error, response.ShouldRetry)); } try { string configString = response.RetryableReadToEnd(); ServerGSDConfig config = JsonConvert.DeserializeObject <ServerGSDConfig>(configString); return(new RetryWrapper <ServerGSDConfig> .CallbackResult(config)); } catch (JsonReaderException e) { return(new RetryWrapper <ServerGSDConfig> .CallbackResult(e, shouldRetry: false)); } } }); if (output.Succeeded) { serverGSDConfig = output.Result; httpStatus = HttpStatusCode.OK; return(true); } GitObjectsHttpException httpException = output.Error as GitObjectsHttpException; if (httpException != null) { httpStatus = httpException.StatusCode; errorMessage = httpException.Message; } if (logErrors) { this.Tracer.RelatedError( new EventMetadata { { "Exception", output.Error.ToString() } }, $"{nameof(this.TryQueryGSDConfig)} failed"); } return(false); }