예제 #1
0
        public IEnumerable<HunkRangeInfo> GetGitDiffFor(ITextDocument textDocument, ITextSnapshot snapshot)
        {
            var content = GetCompleteContent(textDocument, snapshot);
            if (content == null) yield break;

            var filename = textDocument.FilePath;
            var discoveredPath = Repository.Discover(Path.GetFullPath(filename));

            if (!Repository.IsValid(discoveredPath)) yield break;

            using (var repo = new Repository(discoveredPath))
            {
                var retrieveStatus = repo.Index.RetrieveStatus(filename);
                if (retrieveStatus == FileStatus.Untracked || retrieveStatus == FileStatus.Added) yield break;

                content = AdaptCrlf(repo, content, textDocument);

                using (var currentContent = new MemoryStream(content))
                {
                    var newBlob = repo.ObjectDatabase.CreateBlob(currentContent);

                    var directoryInfo = new DirectoryInfo(discoveredPath).Parent;
                    if (directoryInfo == null) yield break;

                    var relativeFilepath = filename.Replace(directoryInfo.FullName + "\\", string.Empty);

                    // Determine 'from' and 'to' trees.
                    var currentBranch = repo.Head.Name;
                    var baseCommitEntry = repo.Config.Get<string>(string.Format("branch.{0}.diffmarginbase", currentBranch));
                    Tree tree = null;
                    if (baseCommitEntry != null)
                    {
                        var baseCommit = repo.Lookup<Commit>(baseCommitEntry.Value);
                        if (baseCommit != null)
                        {
                            // Found a merge base to diff from.
                            tree = baseCommit.Tree;
                        }
                    }
                    tree = tree ?? repo.Head.Tip.Tree;
                    var from = TreeDefinition.From(tree);
                    var treeDefinition = from.Add(relativeFilepath, newBlob, Mode.NonExecutableFile);
                    var to = repo.ObjectDatabase.CreateTree(treeDefinition);

                    var treeChanges = repo.Diff.Compare(tree, to, compareOptions: new CompareOptions { ContextLines = ContextLines, InterhunkLines = 0 });
                    var gitDiffParser = new GitDiffParser(treeChanges.Patch, ContextLines);
                    var hunkRangeInfos = gitDiffParser.Parse();

                    foreach (var hunkRangeInfo in hunkRangeInfos)
                    {
                        yield return hunkRangeInfo;
                    }
                }
            }
        }
예제 #2
0
        public IEnumerable<HunkRangeInfo> GetGitDiffFor(ITextDocument textDocument, ITextSnapshot snapshot)
        {
            var filename = textDocument.FilePath;
            var discoveredPath = Repository.Discover(Path.GetFullPath(filename));

            if (!Repository.IsValid(discoveredPath)) yield break;

            using (var repo = new Repository(discoveredPath))
            {
                var retrieveStatus = repo.Index.RetrieveStatus(filename);
                if (retrieveStatus == FileStatus.Untracked || retrieveStatus == FileStatus.Added) yield break;

                var content = GetCompleteContent(textDocument, snapshot);
                if (content == null) yield break;

                content = AdaptCrlf(repo, content, textDocument);

                using (var currentContent = new MemoryStream(content))
                {
                    var newBlob = repo.ObjectDatabase.CreateBlob(currentContent);

                    var directoryInfo = new DirectoryInfo(discoveredPath).Parent;
                    if (directoryInfo == null) yield break;

                    var relativeFilepath = filename.Replace(directoryInfo.FullName + "\\", string.Empty);

                    var from = TreeDefinition.From(repo.Head.Tip.Tree);

                    if (!repo.ObjectDatabase.Contains(@from[relativeFilepath].TargetId)) yield break;

                    var blob = repo.Lookup<Blob>(@from[relativeFilepath].TargetId);

                    var treeChanges = repo.Diff.Compare(blob, newBlob, new CompareOptions { ContextLines = ContextLines, InterhunkLines = 0 });

                    var gitDiffParser = new GitDiffParser(treeChanges.Patch, ContextLines);
                    var hunkRangeInfos = gitDiffParser.Parse();

                    foreach (var hunkRangeInfo in hunkRangeInfos)
                    {
                        yield return hunkRangeInfo;
                    }
                }
            }
        }
예제 #3
0
        public IEnumerable<HunkRangeInfo> GetGitDiffFor(string filename)
        {
            var p = GetProcess(filename);
            p.StartInfo.Arguments = String.Format(@" diff --unified=0 {0}", filename);

            ActivityLog.LogInformation("GitDiffMargin", "Command:" + p.StartInfo.Arguments);

            p.Start();
            // Do not wait for the child process to exit before
            // reading to the end of its redirected stream.
            // p.WaitForExit();
            // Read the output stream first and then wait.
            var output = p.StandardOutput.ReadToEnd();
            p.WaitForExit();

            ActivityLog.LogInformation("GitDiffMargin", "Git Diff output:" + output);

            var gitDiffParser = new GitDiffParser(output);
            return gitDiffParser.Parse();
        }
예제 #4
0
        public void Parse_WithThreeHunk_ExpectHunkRanges()
        {
            //Arrange
            var gitDiffParser = new GitDiffParser(SecondGitDiff, 0);

            //Act
            var hunkRanges = gitDiffParser.Parse().ToList();

            //Assert
            hunkRanges[0].OriginalHunkRange.StartingLineNumber.ShouldBe(67);
            hunkRanges[0].OriginalHunkRange.NumberOfLines.ShouldBe(2);
            hunkRanges[0].NewHunkRange.StartingLineNumber.ShouldBe(66);
            hunkRanges[0].NewHunkRange.NumberOfLines.ShouldBe(0);

            hunkRanges[1].OriginalHunkRange.StartingLineNumber.ShouldBe(169);
            hunkRanges[1].OriginalHunkRange.NumberOfLines.ShouldBe(0);
            hunkRanges[1].NewHunkRange.StartingLineNumber.ShouldBe(168);
            hunkRanges[1].NewHunkRange.NumberOfLines.ShouldBe(27);

            hunkRanges[2].OriginalHunkRange.StartingLineNumber.ShouldBe(184);
            hunkRanges[2].OriginalHunkRange.NumberOfLines.ShouldBe(2);
            hunkRanges[2].NewHunkRange.StartingLineNumber.ShouldBe(208);
            hunkRanges[2].NewHunkRange.NumberOfLines.ShouldBe(0);
        }
예제 #5
0
        public void Parse_WithOneHunk_ExpectHunkRanges()
        {
            //Arrange
            var gitDiffParser = new GitDiffParser(FirstGitDiff, 0);

            //Act
            var hunkRanges = gitDiffParser.Parse().ToList();

            //Assert
            hunkRanges[0].OriginalHunkRange.StartingLineNumber.ShouldBe(40);
            hunkRanges[0].OriginalHunkRange.NumberOfLines.ShouldBe(0);
            hunkRanges[0].NewHunkRange.StartingLineNumber.ShouldBe(41);
            hunkRanges[0].NewHunkRange.NumberOfLines.ShouldBe(20);
        }
예제 #6
0
        public void Parse_EmptyGitDiff_Expect0HunkRangeInfos()
        {
            //Arrange
            var gitDiffParser = new GitDiffParser(EmptyGitDiff, 0);

            //Act
            var hunkRangeInfos = gitDiffParser.Parse().ToList();

            //Assert
            hunkRangeInfos.Count.ShouldBe(0);
        }
예제 #7
0
        public void Parse_DiffFromLibGit_ExpectThirdHunkRangeToBeAddition()
        {
            //Arrange
            var gitDiffParser = new GitDiffParser(DiffFromLibGit, 0);

            //Act
            var hunkRangeInfos = gitDiffParser.Parse().ToList();

            //Assert
            hunkRangeInfos[2].IsDeletion.ShouldBe(false);
            hunkRangeInfos[2].IsAddition.ShouldBe(true);
            hunkRangeInfos[2].IsModification.ShouldBe(false);
        }
예제 #8
0
        public void Parse_DiffFromLibGit_ExpectSecondHunkRangeOriginalText()
        {
            //Arrange
            var gitDiffParser = new GitDiffParser(DiffFromLibGit, 0);

            //Act
            var hunkRangeInfos = gitDiffParser.Parse().ToList();

            //Assert
            hunkRangeInfos[1].OriginalText.ShouldBe(new List<string> {"    class Class1"});
        }
예제 #9
0
        public void Parse_DiffFromLibGit_Expect5HunkRangeInfos()
        {
            //Arrange
            var gitDiffParser = new GitDiffParser(DiffFromLibGit, 0);

            //Act
            var hunkRangeInfos = gitDiffParser.Parse().ToList();

            //Assert
            hunkRangeInfos.Count.ShouldBe(5);
        }
예제 #10
0
        public IEnumerable <HunkRangeInfo> GetGitDiffFor(ITextDocument textDocument, ITextSnapshot snapshot)
        {
            var filename       = textDocument.FilePath;
            var repositoryPath = GetGitRepository(Path.GetFullPath(filename));

            if (repositoryPath == null)
            {
                yield break;
            }

            using (var repo = new Repository(repositoryPath))
            {
                var workingDirectory = repo.Info.WorkingDirectory;
                if (workingDirectory == null)
                {
                    yield break;
                }

                var retrieveStatus = repo.Index.RetrieveStatus(filename);
                if (retrieveStatus == FileStatus.Nonexistent)
                {
                    // this occurs if a file within the repository itself (not the working copy) is opened.
                    yield break;
                }

                if ((retrieveStatus & FileStatus.Ignored) != 0)
                {
                    // pointless to show diffs for ignored files
                    yield break;
                }

                if (retrieveStatus == FileStatus.Unaltered && !textDocument.IsDirty)
                {
                    // truly unaltered
                    yield break;
                }

                var content = GetCompleteContent(textDocument, snapshot);
                if (content == null)
                {
                    yield break;
                }

                using (var currentContent = new MemoryStream(content))
                {
                    var relativeFilepath = filename;
                    if (relativeFilepath.StartsWith(workingDirectory, StringComparison.OrdinalIgnoreCase))
                    {
                        relativeFilepath = relativeFilepath.Substring(workingDirectory.Length);
                    }

                    var newBlob = repo.ObjectDatabase.CreateBlob(currentContent, relativeFilepath);

                    bool suppressRollback;
                    Blob blob;

                    if ((retrieveStatus & FileStatus.Untracked) != 0 || (retrieveStatus & FileStatus.Added) != 0)
                    {
                        suppressRollback = true;

                        // special handling for added files (would need updating to compare against index)
                        using (var emptyContent = new MemoryStream())
                        {
                            blob = repo.ObjectDatabase.CreateBlob(emptyContent, relativeFilepath);
                        }
                    }
                    else
                    {
                        suppressRollback = false;

                        Commit    from      = repo.Head.Tip;
                        TreeEntry fromEntry = from[relativeFilepath];
                        if (fromEntry == null)
                        {
                            // try again using case-insensitive comparison
                            Tree tree = from.Tree;
                            foreach (string segment in relativeFilepath.Split(Path.DirectorySeparatorChar))
                            {
                                if (tree == null)
                                {
                                    yield break;
                                }

                                fromEntry = tree.FirstOrDefault(i => string.Equals(segment, i.Name, StringComparison.OrdinalIgnoreCase));
                                if (fromEntry == null)
                                {
                                    yield break;
                                }

                                tree = fromEntry.Target as Tree;
                            }
                        }

                        blob = fromEntry.Target as Blob;
                        if (blob == null)
                        {
                            yield break;
                        }
                    }

                    var treeChanges = repo.Diff.Compare(blob, newBlob, new CompareOptions {
                        ContextLines = ContextLines, InterhunkLines = 0
                    });

                    var gitDiffParser  = new GitDiffParser(treeChanges.Patch, ContextLines, suppressRollback);
                    var hunkRangeInfos = gitDiffParser.Parse();

                    foreach (var hunkRangeInfo in hunkRangeInfos)
                    {
                        yield return(hunkRangeInfo);
                    }
                }
            }
        }
예제 #11
0
        public IEnumerable<HunkRangeInfo> GetGitDiffFor(ITextDocument textDocument, ITextSnapshot snapshot)
        {
            var filename = textDocument.FilePath;
            var repositoryPath = GetGitRepository(Path.GetFullPath(filename));
            if (repositoryPath == null)
                yield break;

            using (var repo = new Repository(repositoryPath))
            {
                var workingDirectory = repo.Info.WorkingDirectory;
                if (workingDirectory == null)
                    yield break;

                var retrieveStatus = repo.Index.RetrieveStatus(filename);
                if (retrieveStatus == FileStatus.Nonexistent)
                {
                    // this occurs if a file within the repository itself (not the working copy) is opened.
                    yield break;
                }

                if ((retrieveStatus & FileStatus.Ignored) != 0)
                {
                    // pointless to show diffs for ignored files
                    yield break;
                }

                if (retrieveStatus == FileStatus.Unaltered && !textDocument.IsDirty)
                {
                    // truly unaltered
                    yield break;
                }

                var content = GetCompleteContent(textDocument, snapshot);
                if (content == null) yield break;

                using (var currentContent = new MemoryStream(content))
                {
                    var relativeFilepath = filename;
                    if (relativeFilepath.StartsWith(workingDirectory, StringComparison.OrdinalIgnoreCase))
                        relativeFilepath = relativeFilepath.Substring(workingDirectory.Length);

                    var newBlob = repo.ObjectDatabase.CreateBlob(currentContent, relativeFilepath);

                    bool suppressRollback;
                    Blob blob;

                    if ((retrieveStatus & FileStatus.Untracked) != 0 || (retrieveStatus & FileStatus.Added) != 0)
                    {
                        suppressRollback = true;

                        // special handling for added files (would need updating to compare against index)
                        using (var emptyContent = new MemoryStream())
                        {
                            blob = repo.ObjectDatabase.CreateBlob(emptyContent, relativeFilepath);
                        }
                    }
                    else
                    {
                        suppressRollback = false;

                        Commit from = repo.Head.Tip;
                        TreeEntry fromEntry = from[relativeFilepath];
                        if (fromEntry == null)
                        {
                            // try again using case-insensitive comparison
                            Tree tree = from.Tree;
                            foreach (string segment in relativeFilepath.Split(Path.DirectorySeparatorChar))
                            {
                                if (tree == null)
                                    yield break;

                                fromEntry = tree.FirstOrDefault(i => string.Equals(segment, i.Name, StringComparison.OrdinalIgnoreCase));
                                if (fromEntry == null)
                                    yield break;

                                tree = fromEntry.Target as Tree;
                            }
                        }

                        blob = fromEntry.Target as Blob;
                        if (blob == null)
                            yield break;
                    }

                    var treeChanges = repo.Diff.Compare(blob, newBlob, new CompareOptions { ContextLines = ContextLines, InterhunkLines = 0 });

                    var gitDiffParser = new GitDiffParser(treeChanges.Patch, ContextLines, suppressRollback);
                    var hunkRangeInfos = gitDiffParser.Parse();

                    foreach (var hunkRangeInfo in hunkRangeInfos)
                    {
                        yield return hunkRangeInfo;
                    }
                }
            }
        }
예제 #12
0
        public void Parse_WithOneHunkWithoutLineCount_ExpectHunkRanges()
        {
            //Arrange
            var gitDiffParser = new GitDiffParser(ThirdGitDiff);

            //Act
            var hunkRanges = gitDiffParser.Parse().ToList();

            //Assert
            hunkRanges[0].OriginaleHunkRange.StartingLineNumber.ShouldBe(0);
            hunkRanges[0].OriginaleHunkRange.NumberOfLines.ShouldBe(1);
            hunkRanges[0].NewHunkRange.StartingLineNumber.ShouldBe(0);
            hunkRanges[0].NewHunkRange.NumberOfLines.ShouldBe(1);
        }
예제 #13
0
        public IEnumerable <HunkRangeInfo> GetGitDiffFor(ITextDocument textDocument, ITextSnapshot snapshot)
        {
            var filename       = textDocument.FilePath;
            var discoveredPath = Repository.Discover(Path.GetFullPath(filename));

            if (!Repository.IsValid(discoveredPath))
            {
                yield break;
            }

            using (var repo = new Repository(discoveredPath))
            {
                var retrieveStatus = repo.Index.RetrieveStatus(filename);
                if (retrieveStatus == FileStatus.Untracked || retrieveStatus == FileStatus.Added)
                {
                    yield break;
                }

                var content = GetCompleteContent(textDocument, snapshot);
                if (content == null)
                {
                    yield break;
                }

                content = AdaptCrlf(repo, content, textDocument);

                using (var currentContent = new MemoryStream(content))
                {
                    var newBlob = repo.ObjectDatabase.CreateBlob(currentContent);

                    var directoryInfo = new DirectoryInfo(discoveredPath).Parent;
                    if (directoryInfo == null)
                    {
                        yield break;
                    }

                    var relativeFilepath = filename.Replace(directoryInfo.FullName + "\\", string.Empty);

                    var from = TreeDefinition.From(repo.Head.Tip.Tree);

                    if (!repo.ObjectDatabase.Contains(@from[relativeFilepath].TargetId))
                    {
                        yield break;
                    }

                    var blob = repo.Lookup <Blob>(@from[relativeFilepath].TargetId);

                    var treeChanges = repo.Diff.Compare(blob, newBlob, new CompareOptions {
                        ContextLines = ContextLines, InterhunkLines = 0
                    });

                    var gitDiffParser  = new GitDiffParser(treeChanges.Patch, ContextLines);
                    var hunkRangeInfos = gitDiffParser.Parse();

                    foreach (var hunkRangeInfo in hunkRangeInfos)
                    {
                        yield return(hunkRangeInfo);
                    }
                }
            }
        }
예제 #14
0
        public IEnumerable <HunkRangeInfo> GetGitDiffFor(ITextDocument textDocument, string originalPath, ITextSnapshot snapshot)
        {
            var filename       = textDocument.FilePath;
            var repositoryPath = GetGitRepository(Path.GetFullPath(filename), ref originalPath);

            if (repositoryPath == null)
            {
                yield break;
            }

            using (var repo = new Repository(repositoryPath))
            {
                var workingDirectory = repo.Info.WorkingDirectory;
                if (workingDirectory == null)
                {
                    yield break;
                }

                var retrieveStatus = repo.RetrieveStatus(originalPath);
                if (retrieveStatus == FileStatus.Nonexistent)
                {
                    // this occurs if a file within the repository itself (not the working copy) is opened.
                    yield break;
                }

                if ((retrieveStatus & FileStatus.Ignored) != 0)
                {
                    // pointless to show diffs for ignored files
                    yield break;
                }

                // Determine 'from' tree.
                var    currentBranch   = repo.Head.FriendlyName;
                var    baseCommitEntry = repo.Config.Get <string>(string.Format("branch.{0}.diffmarginbase", currentBranch));
                Commit from            = null;
                if (baseCommitEntry != null)
                {
                    var baseCommit = repo.Lookup <Commit>(baseCommitEntry.Value);
                    if (baseCommit != null)
                    {
                        // Found a merge base to diff from.
                        from = baseCommit;
                    }
                }

                if (from == null &&
                    retrieveStatus == FileStatus.Unaltered &&
                    !textDocument.IsDirty &&
                    Path.GetFullPath(filename) == originalPath)
                {
                    // Truly unaltered. The `IsDirty` check isn't valid for cases where the textDocument is a view of a
                    // temporary copy of the file, since the temporary copy could have been made using unsaved changes
                    // and still appear "not dirty".
                    yield break;
                }

                var content = GetCompleteContent(textDocument, snapshot);
                if (content == null)
                {
                    yield break;
                }

                using (var currentContent = new MemoryStream(content))
                {
                    var relativeFilepath = originalPath;
                    if (relativeFilepath.StartsWith(workingDirectory, StringComparison.OrdinalIgnoreCase))
                    {
                        relativeFilepath = relativeFilepath.Substring(workingDirectory.Length);
                    }

                    relativeFilepath = relativeFilepath.Replace('\\', '/');

                    var newBlob = repo.ObjectDatabase.CreateBlob(currentContent, relativeFilepath);

                    bool suppressRollback;
                    Blob blob;

                    if ((retrieveStatus & FileStatus.NewInWorkdir) != 0 || (retrieveStatus & FileStatus.NewInIndex) != 0)
                    {
                        suppressRollback = true;

                        // special handling for added files (would need updating to compare against index)
                        using (var emptyContent = new MemoryStream())
                        {
                            blob = repo.ObjectDatabase.CreateBlob(emptyContent, relativeFilepath);
                        }
                    }
                    else
                    {
                        suppressRollback = false;

                        from = from ?? repo.Head.Tip;
                        TreeEntry fromEntry = from[relativeFilepath];
                        if (fromEntry == null)
                        {
                            // try again using case-insensitive comparison
                            Tree tree = from.Tree;
                            foreach (string segment in relativeFilepath.Split('/'))
                            {
                                if (tree == null)
                                {
                                    yield break;
                                }

                                fromEntry = tree.FirstOrDefault(i => string.Equals(segment, i.Name, StringComparison.OrdinalIgnoreCase));
                                if (fromEntry == null)
                                {
                                    yield break;
                                }

                                tree = fromEntry.Target as Tree;
                            }
                        }

                        blob = fromEntry.Target as Blob;
                        if (blob == null)
                        {
                            yield break;
                        }
                    }

                    var treeChanges = repo.Diff.Compare(blob, newBlob, new CompareOptions {
                        ContextLines = ContextLines, InterhunkLines = 0
                    });

                    var gitDiffParser  = new GitDiffParser(treeChanges.Patch, ContextLines, suppressRollback);
                    var hunkRangeInfos = gitDiffParser.Parse();

                    foreach (var hunkRangeInfo in hunkRangeInfos)
                    {
                        yield return(hunkRangeInfo);
                    }
                }
            }
        }