private GSDGitObjects CreateTestableGSDGitObjects(MockHttpGitObjects httpObjects, MockFileSystemWithCallbacks fileSystem) { MockTracer tracer = new MockTracer(); GSDEnlistment enlistment = new GSDEnlistment(TestEnlistmentRoot, "https://fakeRepoUrl", "fakeGitBinPath", gvfsHooksRoot: null, authentication: null); enlistment.InitializeCachePathsFromKey(TestLocalCacheRoot, TestObjectRoot); GitRepo repo = new GitRepo(tracer, enlistment, fileSystem, () => new MockLibGit2Repo(tracer)); GSDContext context = new GSDContext(tracer, fileSystem, repo, enlistment); GSDGitObjects dut = new GSDGitObjects(context, httpObjects); return(dut); }
public CommonRepoSetup() { MockTracer tracer = new MockTracer(); string enlistmentRoot = Path.Combine("mock:", "GSD", "UnitTests", "Repo"); GSDEnlistment enlistment = new GSDEnlistment(enlistmentRoot, "fake://repoUrl", "fake://gitBinPath", gvfsHooksRoot: null, authentication: null); enlistment.InitializeCachePathsFromKey("fake:\\gvfsSharedCache", "fakeCacheKey"); this.GitParentPath = enlistment.WorkingDirectoryRoot; this.GSDMetadataPath = enlistment.DotGSDRoot; MockDirectory enlistmentDirectory = new MockDirectory( enlistmentRoot, new MockDirectory[] { new MockDirectory(this.GitParentPath, folders: null, files: null), }, null); enlistmentDirectory.CreateFile(Path.Combine(this.GitParentPath, ".git", "config"), ".git config Contents", createDirectories: true); enlistmentDirectory.CreateFile(Path.Combine(this.GitParentPath, ".git", "HEAD"), ".git HEAD Contents", createDirectories: true); enlistmentDirectory.CreateFile(Path.Combine(this.GitParentPath, ".git", "logs", "HEAD"), "HEAD Contents", createDirectories: true); enlistmentDirectory.CreateFile(Path.Combine(this.GitParentPath, ".git", "info", "always_exclude"), "always_exclude Contents", createDirectories: true); enlistmentDirectory.CreateDirectory(enlistment.GitPackRoot); this.FileSystem = new MockFileSystem(enlistmentDirectory); this.Repository = new MockGitRepo( tracer, enlistment, this.FileSystem); CreateStandardGitTree(this.Repository); this.Context = new GSDContext(tracer, this.FileSystem, this.Repository, enlistment); this.HttpObjects = new MockHttpGitObjects(tracer, enlistment); this.GitObjects = new MockGSDGitObjects(this.Context, this.HttpObjects); }
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); }
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"); } } }