Browse Source

Handle diff formatting when there is nothing to compare with

DiffFormatter now suports either side being null and the log program
will output the diff for the first commit.

Bug: 395791
Change-Id: I378957b57e9ad1f7195ba416f402178453f0ebd3
tags/v3.5.0.201409071800-rc1
Robin Rosenberg 10 years ago
parent
commit
89ad10ec27

+ 3
- 2
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java View File

if (showNotes(c)) if (showNotes(c))
outw.println(); outw.println();


if (c.getParentCount() == 1 && (showNameAndStatusOnly || showPatch))
if (c.getParentCount() <= 1 && (showNameAndStatusOnly || showPatch))
showDiff(c); showDiff(c);
outw.flush(); outw.flush();
} }
} }


private void showDiff(RevCommit c) throws IOException { private void showDiff(RevCommit c) throws IOException {
final RevTree a = c.getParent(0).getTree();
final RevTree a = c.getParentCount() > 0 ? c.getParent(0).getTree()
: null;
final RevTree b = c.getTree(); final RevTree b = c.getTree();


if (showNameAndStatusOnly) if (showNameAndStatusOnly)

+ 78
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java View File

import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.patch.FileHeader; import org.eclipse.jgit.patch.FileHeader;
import org.eclipse.jgit.patch.HunkHeader; import org.eclipse.jgit.patch.HunkHeader;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FileUtils;
assertEquals(expected, actual); assertEquals(expected, actual);
} }


@Test
public void testDiffRootNullToTree() throws Exception {
write(new File(db.getDirectory().getParent(), "test.txt"), "test");
File folder = new File(db.getDirectory().getParent(), "folder");
FileUtils.mkdir(folder);
write(new File(folder, "folder.txt"), "folder");
Git git = new Git(db);
git.add().addFilepattern(".").call();
RevCommit commit = git.commit().setMessage("Initial commit").call();
write(new File(folder, "folder.txt"), "folder change");

ByteArrayOutputStream os = new ByteArrayOutputStream();
DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));
dfmt.setRepository(db);
dfmt.setPathFilter(PathFilter.create("folder"));
dfmt.format(null, commit.getTree().getId());
dfmt.flush();

String actual = os.toString("UTF-8");
String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+ "new file mode 100644\n"
+ "index 0000000..0119635\n"
+ "--- /dev/null\n"
+ "+++ b/folder/folder.txt\n"
+ "@@ -0,0 +1 @@\n"
+ "+folder\n"
+ "\\ No newline at end of file\n";

assertEquals(expected, actual);
}

@Test
public void testDiffRootTreeToNull() throws Exception {
write(new File(db.getDirectory().getParent(), "test.txt"), "test");
File folder = new File(db.getDirectory().getParent(), "folder");
FileUtils.mkdir(folder);
write(new File(folder, "folder.txt"), "folder");
Git git = new Git(db);
git.add().addFilepattern(".").call();
RevCommit commit = git.commit().setMessage("Initial commit").call();
write(new File(folder, "folder.txt"), "folder change");

ByteArrayOutputStream os = new ByteArrayOutputStream();
DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));
dfmt.setRepository(db);
dfmt.setPathFilter(PathFilter.create("folder"));
dfmt.format(commit.getTree().getId(), null);
dfmt.flush();

String actual = os.toString("UTF-8");
String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+ "deleted file mode 100644\n"
+ "index 0119635..0000000\n"
+ "--- a/folder/folder.txt\n"
+ "+++ /dev/null\n"
+ "@@ -1 +0,0 @@\n"
+ "-folder\n"
+ "\\ No newline at end of file\n";

assertEquals(expected, actual);
}

@Test
public void testDiffNullToNull() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
DiffFormatter dfmt = new DiffFormatter(new SafeBufferedOutputStream(os));
dfmt.setRepository(db);
dfmt.format((AnyObjectId) null, null);
dfmt.flush();

String actual = os.toString("UTF-8");
String expected = "";

assertEquals(expected, actual);
}

private static String makeDiffHeader(String pathA, String pathB, private static String makeDiffHeader(String pathA, String pathB,
ObjectId aId, ObjectId aId,
ObjectId bId) { ObjectId bId) {

+ 43
- 17
org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java View File

import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.AmbiguousObjectException; import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.errors.LargeObjectException;
import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.storage.pack.PackConfig;
import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeIterator;
import org.eclipse.jgit.treewalk.filter.AndTreeFilter; import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
* returned. Callers may choose to format these paths themselves, or convert * returned. Callers may choose to format these paths themselves, or convert
* them into {@link FileHeader} instances with a complete edit list by * them into {@link FileHeader} instances with a complete edit list by
* calling {@link #toFileHeader(DiffEntry)}. * calling {@link #toFileHeader(DiffEntry)}.
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
* *
* @param a * @param a
* the old (or previous) side.
* the old (or previous) side or null
* @param b * @param b
* the new (or updated) side.
* the new (or updated) side or null
* @return the paths that are different. * @return the paths that are different.
* @throws IOException * @throws IOException
* trees cannot be read or file contents cannot be read. * trees cannot be read or file contents cannot be read.
assertHaveRepository(); assertHaveRepository();


RevWalk rw = new RevWalk(reader); RevWalk rw = new RevWalk(reader);
return scan(rw.parseTree(a), rw.parseTree(b));
RevTree aTree = a != null ? rw.parseTree(a) : null;
RevTree bTree = b != null ? rw.parseTree(b) : null;
return scan(aTree, bTree);
} }


/** /**
* returned. Callers may choose to format these paths themselves, or convert * returned. Callers may choose to format these paths themselves, or convert
* them into {@link FileHeader} instances with a complete edit list by * them into {@link FileHeader} instances with a complete edit list by
* calling {@link #toFileHeader(DiffEntry)}. * calling {@link #toFileHeader(DiffEntry)}.
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
* *
* @param a * @param a
* the old (or previous) side.
* the old (or previous) side or null
* @param b * @param b
* the new (or updated) side.
* the new (or updated) side or null
* @return the paths that are different. * @return the paths that are different.
* @throws IOException * @throws IOException
* trees cannot be read or file contents cannot be read. * trees cannot be read or file contents cannot be read.
public List<DiffEntry> scan(RevTree a, RevTree b) throws IOException { public List<DiffEntry> scan(RevTree a, RevTree b) throws IOException {
assertHaveRepository(); assertHaveRepository();


CanonicalTreeParser aParser = new CanonicalTreeParser();
CanonicalTreeParser bParser = new CanonicalTreeParser();

aParser.reset(reader, a);
bParser.reset(reader, b);
AbstractTreeIterator aIterator = makeIteratorFromTreeOrNull(a);
AbstractTreeIterator bIterator = makeIteratorFromTreeOrNull(b);
return scan(aIterator, bIterator);
}


return scan(aParser, bParser);
private AbstractTreeIterator makeIteratorFromTreeOrNull(RevTree tree)
throws IncorrectObjectTypeException, IOException {
if (tree != null) {
CanonicalTreeParser parser = new CanonicalTreeParser();
parser.reset(reader, tree);
return parser;
} else
return new EmptyTreeIterator();
} }


/** /**
* *
* The patch is expressed as instructions to modify {@code a} to make it * The patch is expressed as instructions to modify {@code a} to make it
* {@code b}. * {@code b}.
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
* *
* @param a * @param a
* the old (or previous) side.
* the old (or previous) side or null
* @param b * @param b
* the new (or updated) side.
* the new (or updated) side or null
* @throws IOException * @throws IOException
* trees cannot be read, file contents cannot be read, or the * trees cannot be read, file contents cannot be read, or the
* patch cannot be output. * patch cannot be output.
* The patch is expressed as instructions to modify {@code a} to make it * The patch is expressed as instructions to modify {@code a} to make it
* {@code b}. * {@code b}.
* *
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
*
* @param a * @param a
* the old (or previous) side.
* the old (or previous) side or null
* @param b * @param b
* the new (or updated) side.
* the new (or updated) side or null
* @throws IOException * @throws IOException
* trees cannot be read, file contents cannot be read, or the * trees cannot be read, file contents cannot be read, or the
* patch cannot be output. * patch cannot be output.
* *
* The patch is expressed as instructions to modify {@code a} to make it * The patch is expressed as instructions to modify {@code a} to make it
* {@code b}. * {@code b}.
* <p>
* Either side may be null to indicate that the tree has beed added or
* removed. The diff will be computed against nothing.
* *
* @param a * @param a
* the old (or previous) side.
* the old (or previous) side or null
* @param b * @param b
* the new (or updated) side.
* the new (or updated) side or null
* @throws IOException * @throws IOException
* trees cannot be read, file contents cannot be read, or the * trees cannot be read, file contents cannot be read, or the
* patch cannot be output. * patch cannot be output.

Loading…
Cancel
Save