public void CatchesFileNotFoundAfterFileDeleted() { MockFileSystemWithCallbacks fileSystem = new MockFileSystemWithCallbacks(); fileSystem.OnFileExists = () => true; fileSystem.OnOpenFileStream = (path, fileMode, fileAccess) => { if (fileAccess == FileAccess.Write) { return(new MemoryStream()); } throw new FileNotFoundException(); }; MockHttpGitObjects httpObjects = new MockHttpGitObjects(); using (httpObjects.InputStream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(ValidTestObjectFileContents))) { httpObjects.MediaType = GSDConstants.MediaTypes.LooseObjectMediaType; GSDGitObjects dut = this.CreateTestableGSDGitObjects(httpObjects, fileSystem); dut.TryCopyBlobContentStream( ValidTestObjectFileContents, new CancellationToken(), GSDGitObjects.RequestSource.FileStreamCallback, (stream, length) => Assert.Fail("Should not be able to call copy stream callback")) .ShouldEqual(false); } }
private void PrefetchCommits(ITracer tracer, GSDEnlistment enlistment, GitObjectsHttpRequestor objectRequestor, CacheServerInfo cacheServer) { bool success; string error = string.Empty; PhysicalFileSystem fileSystem = new PhysicalFileSystem(); GitRepo repo = new GitRepo(tracer, enlistment, fileSystem); GSDContext context = new GSDContext(tracer, fileSystem, repo, enlistment); GitObjects gitObjects = new GSDGitObjects(context, objectRequestor); if (this.Verbose) { success = new PrefetchStep(context, gitObjects, requireCacheLock: false).TryPrefetchCommitsAndTrees(out error); } else { success = this.ShowStatusWhileRunning( () => new PrefetchStep(context, gitObjects, requireCacheLock: false).TryPrefetchCommitsAndTrees(out error), "Fetching commits and trees " + this.GetCacheServerDisplay(cacheServer, enlistment.RepoUrl)); } if (!success) { this.ReportErrorAndExit(tracer, "Prefetching commits and trees failed: " + error); } }
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 void SucceedsForNormalLookingLooseObjectDownloads() { MockFileSystemWithCallbacks fileSystem = new Mock.FileSystem.MockFileSystemWithCallbacks(); fileSystem.OnFileExists = () => true; fileSystem.OnOpenFileStream = (path, mode, access) => new MemoryStream(); MockHttpGitObjects httpObjects = new MockHttpGitObjects(); using (httpObjects.InputStream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(ValidTestObjectFileContents))) { httpObjects.MediaType = GSDConstants.MediaTypes.LooseObjectMediaType; GSDGitObjects dut = this.CreateTestableGSDGitObjects(httpObjects, fileSystem); dut.TryDownloadAndSaveObject(ValidTestObjectFileContents, GSDGitObjects.RequestSource.FileStreamCallback) .ShouldEqual(GitObjects.DownloadAndSaveObjectResult.Success); } }
private void MountAndStartWorkingDirectoryCallbacks(CacheServerInfo cache) { string error; if (!this.context.Enlistment.Authentication.TryInitialize(this.context.Tracer, this.context.Enlistment, out error)) { this.FailMountAndExit("Failed to obtain git credentials: " + error); } GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(this.context.Tracer, this.context.Enlistment, cache, this.retryConfig); this.gitObjects = new GSDGitObjects(this.context, objectRequestor); GitStatusCache gitStatusCache = (!this.context.Unattended && GSDPlatform.Instance.IsGitStatusCacheSupported()) ? new GitStatusCache(this.context, this.gitStatusCacheConfig) : null; if (gitStatusCache != null) { this.tracer.RelatedInfo("Git status cache enabled. Backoff time: {0}ms", this.gitStatusCacheConfig.BackoffTime.TotalMilliseconds); } else { this.tracer.RelatedInfo("Git status cache is not enabled"); } this.maintenanceScheduler = this.CreateOrReportAndExit(() => new GitMaintenanceScheduler(this.context, this.gitObjects), "Failed to start maintenance scheduler"); int majorVersion; int minorVersion; if (!RepoMetadata.Instance.TryGetOnDiskLayoutVersion(out majorVersion, out minorVersion, out error)) { this.FailMountAndExit("Error: {0}", error); } if (majorVersion != GSDPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion) { this.FailMountAndExit( "Error: On disk version ({0}) does not match current version ({1})", majorVersion, GSDPlatform.Instance.DiskLayoutUpgrade.Version.CurrentMajorVersion); } }
protected bool TryDownloadCommit( string commitId, GSDEnlistment enlistment, GitObjectsHttpRequestor objectRequestor, GSDGitObjects gitObjects, GitRepo repo, out string error, bool checkLocalObjectCache = true) { if (!checkLocalObjectCache || !repo.CommitAndRootTreeExists(commitId)) { if (!gitObjects.TryDownloadCommit(commitId)) { error = "Could not download commit " + commitId + " from: " + Uri.EscapeUriString(objectRequestor.CacheServer.ObjectsEndpointUrl); return(false); } } error = null; return(true); }
private void AssertRetryableExceptionOnDownload( MemoryStream inputStream, string mediaType, Action <GSDGitObjects> download) { MockHttpGitObjects httpObjects = new MockHttpGitObjects(); httpObjects.InputStream = inputStream; httpObjects.MediaType = mediaType; MockFileSystemWithCallbacks fileSystem = new MockFileSystemWithCallbacks(); using (ReusableMemoryStream downloadDestination = new ReusableMemoryStream(string.Empty)) { fileSystem.OnFileExists = () => false; fileSystem.OnOpenFileStream = (path, mode, access) => downloadDestination; GSDGitObjects gitObjects = this.CreateTestableGSDGitObjects(httpObjects, fileSystem); Assert.Throws <RetryableException>(() => download(gitObjects)); inputStream.Dispose(); } }
protected bool TryDownloadRootGitAttributes(GSDEnlistment enlistment, GSDGitObjects gitObjects, GitRepo repo, out string error) { List <DiffTreeResult> rootEntries = new List <DiffTreeResult>(); GitProcess git = new GitProcess(enlistment); GitProcess.Result result = git.LsTree( GSDConstants.DotGit.HeadName, line => rootEntries.Add(DiffTreeResult.ParseFromLsTreeLine(line)), recursive: false); if (result.ExitCodeIsFailure) { error = "Error returned from ls-tree to find " + GSDConstants.SpecialGitFiles.GitAttributes + " file: " + result.Errors; return(false); } DiffTreeResult gitAttributes = rootEntries.FirstOrDefault(entry => entry.TargetPath.Equals(GSDConstants.SpecialGitFiles.GitAttributes)); if (gitAttributes == null) { error = "This branch does not contain a " + GSDConstants.SpecialGitFiles.GitAttributes + " file in the root folder. This file is required by GSD clone"; return(false); } if (!repo.ObjectExists(gitAttributes.TargetSha)) { if (gitObjects.TryDownloadAndSaveObject(gitAttributes.TargetSha, GSDGitObjects.RequestSource.GSDVerb) != GitObjects.DownloadAndSaveObjectResult.Success) { error = "Could not download " + GSDConstants.SpecialGitFiles.GitAttributes + " file"; return(false); } } error = null; return(true); }
private Result CreateClone( ITracer tracer, GSDEnlistment enlistment, GitObjectsHttpRequestor objectRequestor, GitRefs refs, string branch) { Result initRepoResult = this.TryInitRepo(tracer, refs, enlistment); if (!initRepoResult.Success) { return(initRepoResult); } PhysicalFileSystem fileSystem = new PhysicalFileSystem(); string errorMessage; if (!this.TryCreateAlternatesFile(fileSystem, enlistment, out errorMessage)) { return(new Result("Error configuring alternate: " + errorMessage)); } GitRepo gitRepo = new GitRepo(tracer, enlistment, fileSystem); GSDContext context = new GSDContext(tracer, fileSystem, gitRepo, enlistment); GSDGitObjects gitObjects = new GSDGitObjects(context, objectRequestor); if (!this.TryDownloadCommit( refs.GetTipCommitId(branch), enlistment, objectRequestor, gitObjects, gitRepo, out errorMessage)) { return(new Result(errorMessage)); } if (!GSDVerb.TrySetRequiredGitConfigSettings(enlistment) || !GSDVerb.TrySetOptionalGitConfigSettings(enlistment)) { return(new Result("Unable to configure git repo")); } CacheServerResolver cacheServerResolver = new CacheServerResolver(tracer, enlistment); if (!cacheServerResolver.TrySaveUrlToLocalConfig(objectRequestor.CacheServer, out errorMessage)) { return(new Result("Unable to configure cache server: " + errorMessage)); } GitProcess git = new GitProcess(enlistment); string originBranchName = "origin/" + branch; GitProcess.Result createBranchResult = git.CreateBranchWithUpstream(branch, originBranchName); if (createBranchResult.ExitCodeIsFailure) { return(new Result("Unable to create branch '" + originBranchName + "': " + createBranchResult.Errors + "\r\n" + createBranchResult.Output)); } File.WriteAllText( Path.Combine(enlistment.WorkingDirectoryBackingRoot, GSDConstants.DotGit.Head), "ref: refs/heads/" + branch); if (!this.TryDownloadRootGitAttributes(enlistment, gitObjects, gitRepo, out errorMessage)) { return(new Result(errorMessage)); } this.CreateGitScript(enlistment); string installHooksError; if (!HooksInstaller.InstallHooks(context, out installHooksError)) { tracer.RelatedError(installHooksError); return(new Result(installHooksError)); } // TODO: Move this to be after the mount? GitProcess.Result forceCheckoutResult = git.ForceCheckout(branch); if (forceCheckoutResult.ExitCodeIsFailure && forceCheckoutResult.Errors.IndexOf("unable to read tree") > 0) { // It is possible to have the above TryDownloadCommit() fail because we // already have the commit and root tree we intend to check out, but // don't have a tree further down the working directory. If we fail // checkout here, its' because we don't have these trees and the // read-object hook is not available yet. Force downloading the commit // again and retry the checkout. if (!this.TryDownloadCommit( refs.GetTipCommitId(branch), enlistment, objectRequestor, gitObjects, gitRepo, out errorMessage, checkLocalObjectCache: false)) { return(new Result(errorMessage)); } forceCheckoutResult = git.ForceCheckout(branch); } if (!RepoMetadata.TryInitialize(tracer, enlistment.DotGSDRoot, out errorMessage)) { tracer.RelatedError(errorMessage); return(new Result(errorMessage)); } try { RepoMetadata.Instance.SaveCloneMetadata(tracer, enlistment); this.LogEnlistmentInfoAndSetConfigValues(tracer, git, enlistment); } catch (Exception e) { tracer.RelatedError(e.ToString()); return(new Result(e.Message)); } finally { RepoMetadata.Shutdown(); } return(new Result(true)); }