public void ParseFromDiffTreeLine_ModifyBlobLine() { DiffTreeResult expected = new DiffTreeResult() { Operation = DiffTreeResult.Operations.Modify, SourceIsDirectory = false, TargetIsDirectory = false, TargetPath = Path.Combine(RepoRoot, TestBlobPath1.Replace('/', Path.DirectorySeparatorChar)), SourceSha = TestSha1, TargetSha = Test2Sha1 }; DiffTreeResult result = DiffTreeResult.ParseFromDiffTreeLine(ModifyBlobLineFromDiffTree, RepoRoot); this.ValidateDiffTreeResult(expected, result); }
public void ParseFromDiffTreeLine_BlobLineWithTreePath() { DiffTreeResult expected = new DiffTreeResult() { Operation = DiffTreeResult.Operations.Add, SourceIsDirectory = false, TargetIsDirectory = false, TargetPath = Path.Combine(RepoRoot, TestBlobPath2.Replace('/', Path.DirectorySeparatorChar)), SourceSha = null, TargetSha = TestSha1 }; DiffTreeResult result = DiffTreeResult.ParseFromLsTreeLine(BlobLineWithTreePathFromLsTree, RepoRoot); this.ValidateDiffTreeResult(expected, result); }
public void ParseFromDiffTreeLine_AddTreeLine() { DiffTreeResult expected = new DiffTreeResult() { Operation = DiffTreeResult.Operations.Add, SourceIsDirectory = false, TargetIsDirectory = true, TargetPath = CreateTreePath(TestTreePath1), SourceSha = EmptySha1, TargetSha = Test2Sha1 }; DiffTreeResult result = DiffTreeResult.ParseFromDiffTreeLine(AddTreeLineFromDiffTree, RepoRoot); this.ValidateDiffTreeResult(expected, result); }
public void ParseFromDiffTreeLine_TreeLineWithBlobPath() { DiffTreeResult expected = new DiffTreeResult() { Operation = DiffTreeResult.Operations.Add, SourceIsDirectory = false, TargetIsDirectory = true, TargetPath = CreateTreePath(TestTreePath2), SourceSha = null, TargetSha = null }; DiffTreeResult result = DiffTreeResult.ParseFromLsTreeLine(TreeLineWithBlobPathFromLsTree, RepoRoot); this.ValidateDiffTreeResult(expected, result); }
public void ParseFromDiffTreeLine_ModifyTreeLine() { DiffTreeResult expected = new DiffTreeResult() { Operation = DiffTreeResult.Operations.Modify, SourceIsDirectory = true, TargetIsDirectory = true, TargetPath = CreateTreePath(TestTreePath1), SourceSha = TestSha1, TargetSha = Test2Sha1 }; DiffTreeResult result = DiffTreeResult.ParseFromDiffTreeLine(ModifyTreeLineFromDiffTree); this.ValidateDiffTreeResult(expected, result); }
public void ParseFromDiffTreeLine_DeleteBlobLine2() { DiffTreeResult expected = new DiffTreeResult() { Operation = DiffTreeResult.Operations.Delete, SourceIsDirectory = false, TargetIsDirectory = false, TargetPath = TestBlobPath1.Replace('/', Path.DirectorySeparatorChar), SourceSha = TestSha1, TargetSha = EmptySha1 }; DiffTreeResult result = DiffTreeResult.ParseFromDiffTreeLine(DeleteBlobLineFromDiffTree2); this.ValidateDiffTreeResult(expected, result); }
public void ParseFromDiffTreeLine_EmptyRepo() { DiffTreeResult expected = new DiffTreeResult() { Operation = DiffTreeResult.Operations.Modify, SourceIsDirectory = true, TargetIsDirectory = true, TargetPath = TestTreePath1.Replace('/', Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, SourceSha = TestSha1, TargetSha = Test2Sha1 }; DiffTreeResult result = DiffTreeResult.ParseFromDiffTreeLine(ModifyTreeLineFromDiffTree, string.Empty); this.ValidateDiffTreeResult(expected, result); }
public void ParseFromLsTreeLine_BlobLine() { DiffTreeResult expected = new DiffTreeResult() { Operation = DiffTreeResult.Operations.Add, SourceIsDirectory = false, TargetIsDirectory = false, TargetPath = TestTreePath1.Replace('/', Path.DirectorySeparatorChar), SourceSha = null, TargetSha = TestSha1 }; DiffTreeResult result = DiffTreeResult.ParseFromLsTreeLine(BlobLineFromLsTree); this.ValidateDiffTreeResult(expected, result); }
/// <remarks> /// This is not used in a multithreaded method, it doesn't need to be thread-safe /// </remarks> private void EnqueueFileAddOperation(ITracer activity, DiffTreeResult operation) { // Each filepath should be unique according to GVFSPlatform.Instance.Constants.PathComparer. // If there are duplicates, only the last parsed one should remain. if (!this.filesAdded.Add(operation.TargetPath)) { foreach (KeyValuePair <string, HashSet <PathWithMode> > kvp in this.FileAddOperations) { PathWithMode tempPathWithMode = new PathWithMode(operation.TargetPath, 0x0000); if (kvp.Value.Remove(tempPathWithMode)) { break; } } } if (this.stagedFileDeletes.Remove(operation.TargetPath)) { EventMetadata metadata = new EventMetadata(); metadata.Add(nameof(operation.TargetPath), operation.TargetPath); metadata.Add(TracingConstants.MessageKey.WarningMessage, "A case change was attempted. It will not be reflected in the working directory."); activity.RelatedEvent(EventLevel.Warning, "CaseConflict", metadata); } this.FileAddOperations.AddOrUpdate( operation.TargetSha, new HashSet <PathWithMode> { new PathWithMode(operation.TargetPath, operation.TargetMode) }, (key, oldValue) => { oldValue.Add(new PathWithMode(operation.TargetPath, operation.TargetMode)); return(oldValue); }); this.RequiredBlobs.Add(operation.TargetSha); }
/// <remarks> /// This is not used in a multithreaded method, it doesn't need to be thread-safe /// </remarks> private void EnqueueFileAddOperation(ITracer activity, DiffTreeResult operation) { // Each filepath should be case-insensitive unique. If there are duplicates, only the last parsed one should remain. if (!this.filesAdded.Add(operation.TargetPath)) { foreach (KeyValuePair <string, HashSet <string> > kvp in this.FileAddOperations) { if (kvp.Value.Remove(operation.TargetPath)) { break; } } } if (this.stagedFileDeletes.Remove(operation.TargetPath)) { EventMetadata metadata = new EventMetadata(); metadata.Add(nameof(operation.TargetPath), operation.TargetPath); metadata.Add(TracingConstants.MessageKey.WarningMessage, "A case change was attempted. It will not be reflected in the working directory."); activity.RelatedEvent(EventLevel.Warning, "CaseConflict", metadata); } this.FileAddOperations.AddOrUpdate( operation.TargetSha, new HashSet <string>(StringComparer.OrdinalIgnoreCase) { operation.TargetPath }, (key, oldValue) => { oldValue.Add(operation.TargetPath); return(oldValue); }); this.RequiredBlobs.Add(operation.TargetSha); }
protected bool TryDownloadRootGitAttributes(GVFSEnlistment enlistment, GVFSGitObjects gitObjects, GitRepo repo, out string error) { List <DiffTreeResult> rootEntries = new List <DiffTreeResult>(); GitProcess git = new GitProcess(enlistment); GitProcess.Result result = git.LsTree( GVFSConstants.DotGit.HeadName, line => rootEntries.Add(DiffTreeResult.ParseFromLsTreeLine(line, repoRoot: string.Empty)), recursive: false); if (result.ExitCodeIsFailure) { error = "Error returned from ls-tree to find " + GVFSConstants.SpecialGitFiles.GitAttributes + " file: " + result.Errors; return(false); } DiffTreeResult gitAttributes = rootEntries.FirstOrDefault(entry => entry.TargetPath.Equals(GVFSConstants.SpecialGitFiles.GitAttributes)); if (gitAttributes == null) { error = "This branch does not contain a " + GVFSConstants.SpecialGitFiles.GitAttributes + " file in the root folder. This file is required by GVFS clone"; return(false); } if (!repo.ObjectExists(gitAttributes.TargetSha)) { if (gitObjects.TryDownloadAndSaveObject(gitAttributes.TargetSha, GVFSGitObjects.RequestSource.GVFSVerb) != GitObjects.DownloadAndSaveObjectResult.Success) { error = "Could not download " + GVFSConstants.SpecialGitFiles.GitAttributes + " file"; return(false); } } error = null; return(true); }
private void EnqueueOperationsFromDiffTreeLine(ITracer activity, string line) { if (!line.StartsWith(":")) { // Diff-tree starts with metadata we can ignore. // Real diff lines always start with a colon return; } DiffTreeResult result = DiffTreeResult.ParseFromDiffTreeLine(line); if (!this.ShouldIncludeResult(result)) { return; } if (result.Operation == DiffTreeResult.Operations.Unknown || result.Operation == DiffTreeResult.Operations.Unmerged || result.Operation == DiffTreeResult.Operations.CopyEdit || result.Operation == DiffTreeResult.Operations.RenameEdit) { EventMetadata metadata = new EventMetadata(); metadata.Add(nameof(result.TargetPath), result.TargetPath); metadata.Add(nameof(line), line); activity.RelatedError(metadata, "Unexpected diff operation: " + result.Operation); this.HasFailures = true; return; } // Separate and enqueue all directory operations first. if (result.SourceIsDirectory || result.TargetIsDirectory) { switch (result.Operation) { case DiffTreeResult.Operations.Delete: if (!this.stagedDirectoryOperations.Add(result)) { EventMetadata metadata = new EventMetadata(); metadata.Add(nameof(result.TargetPath), result.TargetPath); metadata.Add(TracingConstants.MessageKey.WarningMessage, "A case change was attempted. It will not be reflected in the working directory."); activity.RelatedEvent(EventLevel.Warning, "CaseConflict", metadata); } break; case DiffTreeResult.Operations.Add: case DiffTreeResult.Operations.Modify: if (!this.stagedDirectoryOperations.Add(result)) { EventMetadata metadata = new EventMetadata(); metadata.Add(nameof(result.TargetPath), result.TargetPath); metadata.Add(TracingConstants.MessageKey.WarningMessage, "A case change was attempted. It will not be reflected in the working directory."); activity.RelatedEvent(EventLevel.Warning, "CaseConflict", metadata); // Replace the delete with the add to make sure we don't delete a folder from under ourselves this.stagedDirectoryOperations.Remove(result); this.stagedDirectoryOperations.Add(result); } break; default: activity.RelatedError("Unexpected diff operation from line: {0}", line); break; } } else { switch (result.Operation) { case DiffTreeResult.Operations.Delete: this.EnqueueFileDeleteOperation(activity, result.TargetPath); break; case DiffTreeResult.Operations.Modify: case DiffTreeResult.Operations.Add: this.EnqueueFileAddOperation(activity, result); break; default: activity.RelatedError("Unexpected diff operation from line: {0}", line); break; } } }
public void ParseFromLsTreeLine_NullLine() { Assert.Throws <ArgumentException>(() => DiffTreeResult.ParseFromLsTreeLine(null)); }
public void ParseFromLsTreeLine_EmptyLine() { Assert.Throws <ArgumentException>(() => DiffTreeResult.ParseFromLsTreeLine(string.Empty)); }
public void ParseFromDiffTreeLine_TwoPathLine() { Assert.Throws <ArgumentException>(() => DiffTreeResult.ParseFromDiffTreeLine(TwoPathLineFromDiffTree)); }
public void TestGetIndexOfTypeMarker(string line, string typeMarker, bool expectedResult) { DiffTreeResult.IsLsTreeLineOfType(line, typeMarker).ShouldEqual(expectedResult); }
public void ParseFromDiffTreeLine_TooManyFieldsLine() { Assert.Throws <ArgumentException>(() => DiffTreeResult.ParseFromDiffTreeLine(TooManyFieldsLineFromDiffTree)); }
public void ParseFromDiffTreeLine_NotEnoughFieldsLine() { Assert.Throws <ArgumentException>(() => DiffTreeResult.ParseFromDiffTreeLine(NotEnoughFieldsLineFromDiffTree)); }
public void ParseFromDiffTreeLine_NoColonLine() { Assert.Throws <ArgumentException>(() => DiffTreeResult.ParseFromDiffTreeLine(MissingColonLineFromDiffTree)); }
public void ParseFromLsTreeLine_InvalidLine() { DiffTreeResult.ParseFromLsTreeLine(InvalidLineFromLsTree).ShouldBeNull(); }
private void EnqueueOperationsFromDiffTreeLine(ITracer activity, string repoRoot, string line) { if (!line.StartsWith(":")) { // Diff-tree starts with metadata we can ignore. // Real diff lines always start with a colon return; } DiffTreeResult result = DiffTreeResult.ParseFromDiffTreeLine(line, repoRoot); if (!this.ShouldIncludeResult(result)) { return; } if (result.Operation == DiffTreeResult.Operations.Unknown || result.Operation == DiffTreeResult.Operations.Unmerged) { EventMetadata metadata = new EventMetadata(); metadata.Add("Path", result.TargetFilename); activity.RelatedError(metadata, "Unexpected diff operation: " + result.Operation); this.HasFailures = true; return; } // Separate and enqueue all directory operations first. if (result.SourceIsDirectory || result.TargetIsDirectory) { switch (result.Operation) { case DiffTreeResult.Operations.Delete: if (!this.stagedDirectoryOperations.Add(result)) { EventMetadata metadata = new EventMetadata(); metadata.Add("Filename", result.TargetFilename); metadata.Add(TracingConstants.MessageKey.WarningMessage, "A case change was attempted. It will not be reflected in the working directory."); activity.RelatedEvent(EventLevel.Warning, "CaseConflict", metadata); } break; case DiffTreeResult.Operations.RenameEdit: if (!this.stagedDirectoryOperations.Add(result)) { // This could happen if a directory was deleted and an existing directory was renamed to replace it, but with a different case. EventMetadata metadata = new EventMetadata(); metadata.Add("Filename", result.TargetFilename); metadata.Add(TracingConstants.MessageKey.WarningMessage, "A case change was attempted. It will not be reflected in the working directory."); activity.RelatedEvent(EventLevel.Warning, "CaseConflict", metadata); // The target of RenameEdit is always akin to an Add, so replacing the delete is the safer thing to do. this.stagedDirectoryOperations.Remove(result); this.stagedDirectoryOperations.Add(result); } if (!result.TargetIsDirectory) { // Handle when a directory becomes a file. // Files becoming directories is handled by HandleAllDirectoryOperations this.EnqueueFileAddOperation(activity, result); } if (!result.SourceIsDirectory) { // Handle when a file becomes a directory by deleting the file. this.EnqueueFileDeleteOperation(activity, result.SourceFilename); } break; case DiffTreeResult.Operations.Add: case DiffTreeResult.Operations.Modify: case DiffTreeResult.Operations.CopyEdit: if (!this.stagedDirectoryOperations.Add(result)) { EventMetadata metadata = new EventMetadata(); metadata.Add("Filename", result.TargetFilename); metadata.Add(TracingConstants.MessageKey.WarningMessage, "A case change was attempted. It will not be reflected in the working directory."); activity.RelatedEvent(EventLevel.Warning, "CaseConflict", metadata); // Replace the delete with the add to make sure we don't delete a folder from under ourselves this.stagedDirectoryOperations.Remove(result); this.stagedDirectoryOperations.Add(result); } break; default: activity.RelatedError("Unexpected diff operation from line: {0}", line); break; } } else { switch (result.Operation) { case DiffTreeResult.Operations.Delete: this.EnqueueFileDeleteOperation(activity, result.TargetFilename); break; case DiffTreeResult.Operations.RenameEdit: this.EnqueueFileAddOperation(activity, result); this.EnqueueFileDeleteOperation(activity, result.SourceFilename); break; case DiffTreeResult.Operations.Modify: case DiffTreeResult.Operations.CopyEdit: case DiffTreeResult.Operations.Add: this.EnqueueFileAddOperation(activity, result); break; default: activity.RelatedError("Unexpected diff operation from line: {0}", line); break; } } }
public void ParseFromLsTreeLine_NullRepoRoot() { Assert.Throws <ArgumentNullException>(() => DiffTreeResult.ParseFromLsTreeLine(BlobLineFromLsTree, null)); }
public void ParseFromDiffTreeLine_NullRepo() { Assert.Throws <ArgumentNullException>(() => DiffTreeResult.ParseFromDiffTreeLine(ModifyTreeLineFromDiffTree, null)); }