public virtual void TestLinesAllDeletedShortenedWalk() { Git git = new Git(db); string[] content1 = new string[] { "first", "second", "third" }; WriteTrashFile("file.txt", Join(content1)); git.Add().AddFilepattern("file.txt").Call(); git.Commit().SetMessage("create file").Call(); string[] content2 = new string[] { string.Empty }; WriteTrashFile("file.txt", Join(content2)); git.Add().AddFilepattern("file.txt").Call(); git.Commit().SetMessage("create file").Call(); WriteTrashFile("file.txt", Join(content1)); git.Add().AddFilepattern("file.txt").Call(); RevCommit c3 = git.Commit().SetMessage("create file").Call(); BlameGenerator generator = new BlameGenerator(db, "file.txt"); try { generator.Push(null, db.Resolve(Constants.HEAD)); NUnit.Framework.Assert.AreEqual(3, generator.GetResultContents().Size()); NUnit.Framework.Assert.IsTrue(generator.Next()); NUnit.Framework.Assert.AreEqual(c3, generator.GetSourceCommit()); NUnit.Framework.Assert.AreEqual(0, generator.GetResultStart()); NUnit.Framework.Assert.AreEqual(3, generator.GetResultEnd()); NUnit.Framework.Assert.IsFalse(generator.Next()); } finally { generator.Release(); } }
/// <summary> /// Generate a list of lines with information about when the lines were /// introduced into the file path. /// </summary> /// <remarks> /// Generate a list of lines with information about when the lines were /// introduced into the file path. /// </remarks> /// <returns>list of lines</returns> /// <exception cref="NGit.Api.Errors.GitAPIException"></exception> public override BlameResult Call() { CheckCallable(); BlameGenerator gen = new BlameGenerator(repo, path); try { if (diffAlgorithm != null) { gen.SetDiffAlgorithm(diffAlgorithm); } if (textComparator != null) { gen.SetTextComparator(textComparator); } if (followFileRenames != null) { gen.SetFollowFileRenames(followFileRenames); } if (reverseEndCommits != null) { gen.Reverse(startCommit, reverseEndCommits); } else { if (startCommit != null) { gen.Push(null, startCommit); } else { gen.Push(null, repo.Resolve(Constants.HEAD)); if (!repo.IsBare) { DirCache dc = repo.ReadDirCache(); int entry = dc.FindEntry(path); if (0 <= entry) { gen.Push(null, dc.GetEntry(entry).GetObjectId()); } FilePath inTree = new FilePath(repo.WorkTree, path); if (inTree.IsFile()) { gen.Push(null, new RawText(inTree)); } } } } return(gen.ComputeBlameResult()); } catch (IOException e) { throw new JGitInternalException(e.Message, e); } finally { gen.Release(); } }
/// <summary>Construct a new BlameResult for a generator.</summary> /// <remarks>Construct a new BlameResult for a generator.</remarks> /// <param name="gen">the generator the result will consume records from.</param> /// <returns> /// the new result object. null if the generator cannot find the path /// it starts from. /// </returns> /// <exception cref="System.IO.IOException">the repository cannot be read.</exception> public static NGit.Blame.BlameResult Create(BlameGenerator gen) { string path = gen.GetResultPath(); RawText contents = gen.GetResultContents(); if (contents == null) { gen.Release(); return null; } return new NGit.Blame.BlameResult(gen, path, contents); }
public virtual void TestBoundLineDelete() { Git git = new Git(db); string[] content1 = new string[] { "first", "second" }; WriteTrashFile("file.txt", Join(content1)); git.Add().AddFilepattern("file.txt").Call(); RevCommit c1 = git.Commit().SetMessage("create file").Call(); string[] content2 = new string[] { "third", "first", "second" }; WriteTrashFile("file.txt", Join(content2)); git.Add().AddFilepattern("file.txt").Call(); RevCommit c2 = git.Commit().SetMessage("create file").Call(); BlameGenerator generator = new BlameGenerator(db, "file.txt"); try { generator.Push(null, db.Resolve(Constants.HEAD)); NUnit.Framework.Assert.AreEqual(3, generator.GetResultContents().Size()); NUnit.Framework.Assert.IsTrue(generator.Next()); NUnit.Framework.Assert.AreEqual(c2, generator.GetSourceCommit()); NUnit.Framework.Assert.AreEqual(1, generator.GetRegionLength()); NUnit.Framework.Assert.AreEqual(0, generator.GetResultStart()); NUnit.Framework.Assert.AreEqual(1, generator.GetResultEnd()); NUnit.Framework.Assert.AreEqual(0, generator.GetSourceStart()); NUnit.Framework.Assert.AreEqual(1, generator.GetSourceEnd()); NUnit.Framework.Assert.AreEqual("file.txt", generator.GetSourcePath()); NUnit.Framework.Assert.IsTrue(generator.Next()); NUnit.Framework.Assert.AreEqual(c1, generator.GetSourceCommit()); NUnit.Framework.Assert.AreEqual(2, generator.GetRegionLength()); NUnit.Framework.Assert.AreEqual(1, generator.GetResultStart()); NUnit.Framework.Assert.AreEqual(3, generator.GetResultEnd()); NUnit.Framework.Assert.AreEqual(0, generator.GetSourceStart()); NUnit.Framework.Assert.AreEqual(2, generator.GetSourceEnd()); NUnit.Framework.Assert.AreEqual("file.txt", generator.GetSourcePath()); NUnit.Framework.Assert.IsFalse(generator.Next()); } finally { generator.Release(); } }
public virtual void TestRenamedBoundLineDelete() { Git git = new Git(db); string FILENAME_1 = "subdir/file1.txt"; string FILENAME_2 = "subdir/file2.txt"; string[] content1 = new string[] { "first", "second" }; WriteTrashFile(FILENAME_1, Join(content1)); git.Add().AddFilepattern(FILENAME_1).Call(); RevCommit c1 = git.Commit().SetMessage("create file1").Call(); // rename it WriteTrashFile(FILENAME_2, Join(content1)); git.Add().AddFilepattern(FILENAME_2).Call(); DeleteTrashFile(FILENAME_1); git.Rm().AddFilepattern(FILENAME_1).Call(); git.Commit().SetMessage("rename file1.txt to file2.txt").Call(); // and change the new file string[] content2 = new string[] { "third", "first", "second" }; WriteTrashFile(FILENAME_2, Join(content2)); git.Add().AddFilepattern(FILENAME_2).Call(); RevCommit c2 = git.Commit().SetMessage("change file2").Call(); BlameGenerator generator = new BlameGenerator(db, FILENAME_2); try { generator.Push(null, db.Resolve(Constants.HEAD)); NUnit.Framework.Assert.AreEqual(3, generator.GetResultContents().Size()); NUnit.Framework.Assert.IsTrue(generator.Next()); NUnit.Framework.Assert.AreEqual(c2, generator.GetSourceCommit()); NUnit.Framework.Assert.AreEqual(1, generator.GetRegionLength()); NUnit.Framework.Assert.AreEqual(0, generator.GetResultStart()); NUnit.Framework.Assert.AreEqual(1, generator.GetResultEnd()); NUnit.Framework.Assert.AreEqual(0, generator.GetSourceStart()); NUnit.Framework.Assert.AreEqual(1, generator.GetSourceEnd()); NUnit.Framework.Assert.AreEqual(FILENAME_2, generator.GetSourcePath()); NUnit.Framework.Assert.IsTrue(generator.Next()); NUnit.Framework.Assert.AreEqual(c1, generator.GetSourceCommit()); NUnit.Framework.Assert.AreEqual(2, generator.GetRegionLength()); NUnit.Framework.Assert.AreEqual(1, generator.GetResultStart()); NUnit.Framework.Assert.AreEqual(3, generator.GetResultEnd()); NUnit.Framework.Assert.AreEqual(0, generator.GetSourceStart()); NUnit.Framework.Assert.AreEqual(2, generator.GetSourceEnd()); NUnit.Framework.Assert.AreEqual(FILENAME_1, generator.GetSourcePath()); NUnit.Framework.Assert.IsFalse(generator.Next()); } finally { generator.Release(); } // and test again with other BlameGenerator API: generator = new BlameGenerator(db, FILENAME_2); try { generator.Push(null, db.Resolve(Constants.HEAD)); BlameResult result = generator.ComputeBlameResult(); NUnit.Framework.Assert.AreEqual(3, result.GetResultContents().Size()); NUnit.Framework.Assert.AreEqual(c2, result.GetSourceCommit(0)); NUnit.Framework.Assert.AreEqual(FILENAME_2, result.GetSourcePath(0)); NUnit.Framework.Assert.AreEqual(c1, result.GetSourceCommit(1)); NUnit.Framework.Assert.AreEqual(FILENAME_1, result.GetSourcePath(1)); NUnit.Framework.Assert.AreEqual(c1, result.GetSourceCommit(2)); NUnit.Framework.Assert.AreEqual(FILENAME_1, result.GetSourcePath(2)); } finally { generator.Release(); } }
private void LoadFrom(BlameGenerator gen) { RevCommit srcCommit = gen.GetSourceCommit(); PersonIdent srcAuthor = gen.GetSourceAuthor(); PersonIdent srcCommitter = gen.GetSourceCommitter(); string srcPath = gen.GetSourcePath(); int srcLine = gen.GetSourceStart(); int resLine = gen.GetResultStart(); int resEnd = gen.GetResultEnd(); for (; resLine < resEnd; resLine++) { // Reverse blame can generate multiple results for the same line. // Favor the first one selected, as this is the oldest and most // likely to be nearest to the inquiry made by the user. if (sourceLines[resLine] != 0) { continue; } sourceCommits[resLine] = srcCommit; sourceAuthors[resLine] = srcAuthor; sourceCommitters[resLine] = srcCommitter; sourcePaths[resLine] = srcPath; // Since sourceLines is 1-based to permit hasSourceData to use 0 to // mean the line has not been annotated yet, pre-increment instead // of the traditional post-increment when making the assignment. sourceLines[resLine] = ++srcLine; } }
/// <summary>Compute until the entire range has been populated.</summary> /// <remarks>Compute until the entire range has been populated.</remarks> /// <param name="start">first index to examine.</param> /// <param name="end">last index to examine.</param> /// <exception cref="System.IO.IOException">the repository cannot be read.</exception> public virtual void ComputeRange(int start, int end) { BlameGenerator gen = generator; if (gen == null) { return; } while (start < end) { if (HasSourceData(start, end)) { return; } if (!gen.Next()) { gen.Release(); generator = null; return; } LoadFrom(gen); // If the result contains either end of our current range bounds, // update the bounds to avoid scanning that section during the // next loop iteration. int resLine = gen.GetResultStart(); int resEnd = gen.GetResultEnd(); if (resLine <= start && start < resEnd) { start = resEnd; } if (resLine <= end && end < resEnd) { end = resLine; } } }
/// <summary>Compute the next available segment and return the first index.</summary> /// <remarks> /// Compute the next available segment and return the first index. /// <p> /// Computes one segment and returns to the caller the first index that is /// available. After return the caller can also inspect /// <see cref="LastLength()">LastLength()</see> /// to determine how many lines of the result were computed. /// </remarks> /// <returns>index that is now available. -1 if no more are available.</returns> /// <exception cref="System.IO.IOException">the repository cannot be read.</exception> public virtual int ComputeNext() { BlameGenerator gen = generator; if (gen == null) { return -1; } if (gen.Next()) { LoadFrom(gen); lastLength = gen.GetRegionLength(); return gen.GetResultStart(); } else { gen.Release(); generator = null; return -1; } }
/// <summary>Compute all pending information.</summary> /// <remarks>Compute all pending information.</remarks> /// <exception cref="System.IO.IOException">the repository cannot be read.</exception> public virtual void ComputeAll() { BlameGenerator gen = generator; if (gen == null) { return; } try { while (gen.Next()) { LoadFrom(gen); } } finally { gen.Release(); generator = null; } }
internal BlameResult(BlameGenerator bg, string path, RawText text) { generator = bg; resultPath = path; resultContents = text; int cnt = text.Size(); sourceCommits = new RevCommit[cnt]; sourceAuthors = new PersonIdent[cnt]; sourceCommitters = new PersonIdent[cnt]; sourceLines = new int[cnt]; sourcePaths = new string[cnt]; }
public virtual void TestRenamedBoundLineDelete() { Git git = new Git(db); string FILENAME_1 = "subdir/file1.txt"; string FILENAME_2 = "subdir/file2.txt"; string[] content1 = new string[] { "first", "second" }; WriteTrashFile(FILENAME_1, Join(content1)); git.Add().AddFilepattern(FILENAME_1).Call(); RevCommit c1 = git.Commit().SetMessage("create file1").Call(); // rename it WriteTrashFile(FILENAME_2, Join(content1)); git.Add().AddFilepattern(FILENAME_2).Call(); DeleteTrashFile(FILENAME_1); git.Rm().AddFilepattern(FILENAME_1).Call(); git.Commit().SetMessage("rename file1.txt to file2.txt").Call(); // and change the new file string[] content2 = new string[] { "third", "first", "second" }; WriteTrashFile(FILENAME_2, Join(content2)); git.Add().AddFilepattern(FILENAME_2).Call(); RevCommit c2 = git.Commit().SetMessage("change file2").Call(); BlameGenerator generator = new BlameGenerator(db, FILENAME_2); try { generator.Push(null, db.Resolve(Constants.HEAD)); NUnit.Framework.Assert.AreEqual(3, generator.GetResultContents().Size()); NUnit.Framework.Assert.IsTrue(generator.Next()); NUnit.Framework.Assert.AreEqual(c2, generator.GetSourceCommit()); NUnit.Framework.Assert.AreEqual(1, generator.GetRegionLength()); NUnit.Framework.Assert.AreEqual(0, generator.GetResultStart()); NUnit.Framework.Assert.AreEqual(1, generator.GetResultEnd()); NUnit.Framework.Assert.AreEqual(0, generator.GetSourceStart()); NUnit.Framework.Assert.AreEqual(1, generator.GetSourceEnd()); NUnit.Framework.Assert.AreEqual(FILENAME_2, generator.GetSourcePath()); NUnit.Framework.Assert.IsTrue(generator.Next()); NUnit.Framework.Assert.AreEqual(c1, generator.GetSourceCommit()); NUnit.Framework.Assert.AreEqual(2, generator.GetRegionLength()); NUnit.Framework.Assert.AreEqual(1, generator.GetResultStart()); NUnit.Framework.Assert.AreEqual(3, generator.GetResultEnd()); NUnit.Framework.Assert.AreEqual(0, generator.GetSourceStart()); NUnit.Framework.Assert.AreEqual(2, generator.GetSourceEnd()); NUnit.Framework.Assert.AreEqual(FILENAME_1, generator.GetSourcePath()); NUnit.Framework.Assert.IsFalse(generator.Next()); } finally { generator.Release(); } // and test again with other BlameGenerator API: generator = new BlameGenerator(db, FILENAME_2); try { generator.Push(null, db.Resolve(Constants.HEAD)); BlameResult result = generator.ComputeBlameResult(); NUnit.Framework.Assert.AreEqual(3, result.GetResultContents().Size()); NUnit.Framework.Assert.AreEqual(c2, result.GetSourceCommit(0)); NUnit.Framework.Assert.AreEqual(FILENAME_2, result.GetSourcePath(0)); NUnit.Framework.Assert.AreEqual(c1, result.GetSourceCommit(1)); NUnit.Framework.Assert.AreEqual(FILENAME_1, result.GetSourcePath(1)); NUnit.Framework.Assert.AreEqual(c1, result.GetSourceCommit(2)); NUnit.Framework.Assert.AreEqual(FILENAME_1, result.GetSourcePath(2)); } finally { generator.Release(); } }