diff options
Diffstat (limited to 'org.eclipse.jgit.pgm/src/org')
3 files changed, 253 insertions, 76 deletions
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java index fc1e400ab0..77ed73048d 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java @@ -45,31 +45,34 @@ package org.eclipse.jgit.pgm; +import java.io.BufferedOutputStream; import java.io.IOException; -import java.io.PrintStream; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.Option; - +import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffFormatter; -import org.eclipse.jgit.diff.MyersDiff; -import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.diff.RawTextIgnoreAllWhitespace; import org.eclipse.jgit.diff.RawTextIgnoreLeadingWhitespace; import org.eclipse.jgit.diff.RawTextIgnoreTrailingWhitespace; import org.eclipse.jgit.diff.RawTextIgnoreWhitespaceChange; -import org.eclipse.jgit.lib.FileMode; -import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.diff.RenameDetector; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.TextProgressMonitor; import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.filter.AndTreeFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; @Command(common = true, usage = "usage_ShowDiffs") class Diff extends TextBuiltin { + private final DiffFormatter diffFmt = new DiffFormatter( // + new BufferedOutputStream(System.out)); + @Argument(index = 0, metaVar = "metaVar_treeish", required = true) void tree_0(final AbstractTreeIterator c) { trees.add(c); @@ -78,25 +81,101 @@ class Diff extends TextBuiltin { @Argument(index = 1, metaVar = "metaVar_treeish", required = true) private final List<AbstractTreeIterator> trees = new ArrayList<AbstractTreeIterator>(); - @Option(name = "--", metaVar = "metaVar_port", multiValued = true, handler = PathTreeFilterHandler.class) + @Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = PathTreeFilterHandler.class) private TreeFilter pathFilter = TreeFilter.ALL; + // BEGIN -- Options shared with Log + @Option(name = "-p", usage = "usage_showPatch") + boolean showPatch; + + @Option(name = "-M", usage = "usage_detectRenames") + private boolean detectRenames; + + @Option(name = "-l", usage = "usage_renameLimit") + private Integer renameLimit; + + @Option(name = "--name-status", usage = "usage_nameStatus") + private boolean showNameAndStatusOnly; + @Option(name = "--ignore-space-at-eol") - private boolean ignoreWsTrailing; + void ignoreSpaceAtEol(@SuppressWarnings("unused") boolean on) { + diffFmt.setRawTextFactory(RawTextIgnoreTrailingWhitespace.FACTORY); + } @Option(name = "--ignore-leading-space") - private boolean ignoreWsLeading; + void ignoreLeadingSpace(@SuppressWarnings("unused") boolean on) { + diffFmt.setRawTextFactory(RawTextIgnoreLeadingWhitespace.FACTORY); + } @Option(name = "-b", aliases = { "--ignore-space-change" }) - private boolean ignoreWsChange; + void ignoreSpaceChange(@SuppressWarnings("unused") boolean on) { + diffFmt.setRawTextFactory(RawTextIgnoreWhitespaceChange.FACTORY); + } @Option(name = "-w", aliases = { "--ignore-all-space" }) - private boolean ignoreWsAll; + void ignoreAllSpace(@SuppressWarnings("unused") boolean on) { + diffFmt.setRawTextFactory(RawTextIgnoreAllWhitespace.FACTORY); + } + + @Option(name = "-U", aliases = { "--unified" }, metaVar = "metaVar_linesOfContext") + void unified(int lines) { + diffFmt.setContext(lines); + } + + @Option(name = "--abbrev", metaVar = "n") + void abbrev(int lines) { + diffFmt.setAbbreviationLength(lines); + } - private DiffFormatter fmt = new DiffFormatter(); + @Option(name = "--full-index") + void abbrev(@SuppressWarnings("unused") boolean on) { + diffFmt.setAbbreviationLength(Constants.OBJECT_ID_STRING_LENGTH); + } + + // END -- Options shared with Log @Override protected void run() throws Exception { + List<DiffEntry> files = scan(); + + if (showNameAndStatusOnly) { + nameStatus(out, files); + out.flush(); + + } else { + diffFmt.setRepository(db); + diffFmt.format(files); + diffFmt.flush(); + } + } + + static void nameStatus(PrintWriter out, List<DiffEntry> files) { + for (DiffEntry ent : files) { + switch (ent.getChangeType()) { + case ADD: + out.println("A\t" + ent.getNewName()); + break; + case DELETE: + out.println("D\t" + ent.getOldName()); + break; + case MODIFY: + out.println("M\t" + ent.getNewName()); + break; + case COPY: + out.format("C%1$03d\t%2$s\t%3$s", ent.getScore(), // + ent.getOldName(), ent.getNewName()); + out.println(); + break; + case RENAME: + out.format("R%1$03d\t%2$s\t%3$s", ent.getScore(), // + ent.getOldName(), ent.getNewName()); + out.println(); + break; + } + } + } + + private List<DiffEntry> scan() throws IOException { final TreeWalk walk = new TreeWalk(db); walk.reset(); walk.setRecursive(true); @@ -104,65 +183,14 @@ class Diff extends TextBuiltin { walk.addTree(i); walk.setFilter(AndTreeFilter.create(TreeFilter.ANY_DIFF, pathFilter)); - while (walk.next()) - outputDiff(System.out, walk.getPathString(), - walk.getObjectId(0), walk.getFileMode(0), - walk.getObjectId(1), walk.getFileMode(1)); - } - - protected void outputDiff(PrintStream out, String path, - ObjectId id1, FileMode mode1, ObjectId id2, FileMode mode2) throws IOException { - String name1 = "a/" + path; - String name2 = "b/" + path; - out.println("diff --git " + name1 + " " + name2); - boolean isNew=false; - boolean isDelete=false; - if (id1.equals(ObjectId.zeroId())) { - out.println("new file mode " + mode2); - isNew=true; - } else if (id2.equals(ObjectId.zeroId())) { - out.println("deleted file mode " + mode1); - isDelete=true; - } else if (!mode1.equals(mode2)) { - out.println("old mode " + mode1); - out.println("new mode " + mode2); + List<DiffEntry> files = DiffEntry.scan(walk); + if (detectRenames) { + RenameDetector rd = new RenameDetector(db); + if (renameLimit != null) + rd.setRenameLimit(renameLimit.intValue()); + rd.addAll(files); + files = rd.compute(new TextProgressMonitor()); } - out.println("index " + id1.abbreviate(db, 7).name() - + ".." + id2.abbreviate(db, 7).name() - + (mode1.equals(mode2) ? " " + mode1 : "")); - out.println("--- " + (isNew ? "/dev/null" : name1)); - out.println("+++ " + (isDelete ? "/dev/null" : name2)); - - byte[] aRaw = getRawBytes(id1); - byte[] bRaw = getRawBytes(id2); - - if (RawText.isBinary(aRaw) || RawText.isBinary(bRaw)) { - out.println("Binary files differ"); - return; - } - - RawText a = getRawText(aRaw); - RawText b = getRawText(bRaw); - MyersDiff diff = new MyersDiff(a, b); - fmt.formatEdits(out, a, b, diff.getEdits()); - } - - private byte[] getRawBytes(ObjectId id) throws IOException { - if (id.equals(ObjectId.zeroId())) - return new byte[] {}; - return db.openBlob(id).getCachedBytes(); - } - - private RawText getRawText(byte[] raw) { - if (ignoreWsAll) - return new RawTextIgnoreAllWhitespace(raw); - else if (ignoreWsTrailing) - return new RawTextIgnoreTrailingWhitespace(raw); - else if (ignoreWsChange) - return new RawTextIgnoreWhitespaceChange(raw); - else if (ignoreWsLeading) - return new RawTextIgnoreLeadingWhitespace(raw); - else - return new RawText(raw); + return files; } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java index 9aa197e4ab..48a05915e4 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java @@ -45,22 +45,39 @@ package org.eclipse.jgit.pgm; +import java.io.BufferedOutputStream; +import java.io.IOException; import java.text.DateFormat; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; -import org.kohsuke.args4j.Option; +import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.diff.RawTextIgnoreAllWhitespace; +import org.eclipse.jgit.diff.RawTextIgnoreLeadingWhitespace; +import org.eclipse.jgit.diff.RawTextIgnoreTrailingWhitespace; +import org.eclipse.jgit.diff.RawTextIgnoreWhitespaceChange; +import org.eclipse.jgit.diff.RenameDetector; +import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.revwalk.FollowFilter; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.filter.AndTreeFilter; +import org.eclipse.jgit.treewalk.filter.TreeFilter; +import org.kohsuke.args4j.Option; @Command(common = true, usage = "usage_viewCommitHistory") class Log extends RevWalkTextBuiltin { @@ -68,11 +85,64 @@ class Log extends RevWalkTextBuiltin { private final DateFormat fmt; + private final DiffFormatter diffFmt = new DiffFormatter( // + new BufferedOutputStream(System.out)); + private Map<AnyObjectId, Set<Ref>> allRefsByPeeledObjectId; @Option(name="--decorate", usage="usage_showRefNamesMatchingCommits") private boolean decorate; + // BEGIN -- Options shared with Diff + @Option(name = "-p", usage = "usage_showPatch") + boolean showPatch; + + @Option(name = "-M", usage = "usage_detectRenames") + private boolean detectRenames; + + @Option(name = "-l", usage = "usage_renameLimit") + private Integer renameLimit; + + @Option(name = "--name-status", usage = "usage_nameStatus") + private boolean showNameAndStatusOnly; + + @Option(name = "--ignore-space-at-eol") + void ignoreSpaceAtEol(@SuppressWarnings("unused") boolean on) { + diffFmt.setRawTextFactory(RawTextIgnoreTrailingWhitespace.FACTORY); + } + + @Option(name = "--ignore-leading-space") + void ignoreLeadingSpace(@SuppressWarnings("unused") boolean on) { + diffFmt.setRawTextFactory(RawTextIgnoreLeadingWhitespace.FACTORY); + } + + @Option(name = "-b", aliases = { "--ignore-space-change" }) + void ignoreSpaceChange(@SuppressWarnings("unused") boolean on) { + diffFmt.setRawTextFactory(RawTextIgnoreWhitespaceChange.FACTORY); + } + + @Option(name = "-w", aliases = { "--ignore-all-space" }) + void ignoreAllSpace(@SuppressWarnings("unused") boolean on) { + diffFmt.setRawTextFactory(RawTextIgnoreAllWhitespace.FACTORY); + } + + @Option(name = "-U", aliases = { "--unified" }, metaVar = "metaVar_linesOfContext") + void unified(int lines) { + diffFmt.setContext(lines); + } + + @Option(name = "--abbrev", metaVar = "metaVar_n") + void abbrev(int lines) { + diffFmt.setAbbreviationLength(lines); + } + + @Option(name = "--full-index") + void abbrev(@SuppressWarnings("unused") boolean on) { + diffFmt.setAbbreviationLength(Constants.OBJECT_ID_STRING_LENGTH); + } + + // END -- Options shared with Diff + Log() { fmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZZZZ", Locale.US); } @@ -120,6 +190,77 @@ class Log extends RevWalkTextBuiltin { } out.println(); + if (c.getParentCount() == 1 && (showNameAndStatusOnly || showPatch)) + showDiff(c); out.flush(); } + + private void showDiff(RevCommit c) throws IOException { + final TreeWalk tw = new TreeWalk(db); + tw.setRecursive(true); + tw.reset(); + tw.addTree(c.getParent(0).getTree()); + tw.addTree(c.getTree()); + tw.setFilter(AndTreeFilter.create(pathFilter, TreeFilter.ANY_DIFF)); + + List<DiffEntry> files = DiffEntry.scan(tw); + if (pathFilter instanceof FollowFilter && isAdd(files)) { + // The file we are following was added here, find where it + // came from so we can properly show the rename or copy, + // then continue digging backwards. + // + tw.reset(); + tw.addTree(c.getParent(0).getTree()); + tw.addTree(c.getTree()); + tw.setFilter(TreeFilter.ANY_DIFF); + files = updateFollowFilter(detectRenames(DiffEntry.scan(tw))); + + } else if (detectRenames) + files = detectRenames(files); + + if (showNameAndStatusOnly) { + Diff.nameStatus(out, files); + + } else { + diffFmt.setRepository(db); + diffFmt.format(files); + diffFmt.flush(); + } + out.println(); + } + + private List<DiffEntry> detectRenames(List<DiffEntry> files) + throws IOException { + RenameDetector rd = new RenameDetector(db); + if (renameLimit != null) + rd.setRenameLimit(renameLimit.intValue()); + rd.addAll(files); + return rd.compute(); + } + + private boolean isAdd(List<DiffEntry> files) { + String oldPath = ((FollowFilter) pathFilter).getPath(); + for (DiffEntry ent : files) { + if (ent.getChangeType() == ChangeType.ADD + && ent.getNewName().equals(oldPath)) + return true; + } + return false; + } + + private List<DiffEntry> updateFollowFilter(List<DiffEntry> files) { + String oldPath = ((FollowFilter) pathFilter).getPath(); + for (DiffEntry ent : files) { + if (isRename(ent) && ent.getNewName().equals(oldPath)) { + pathFilter = FollowFilter.create(ent.getOldName()); + return Collections.singletonList(ent); + } + } + return Collections.emptyList(); + } + + private static boolean isRename(DiffEntry ent) { + return ent.getChangeType() == ChangeType.RENAME + || ent.getChangeType() == ChangeType.COPY; + } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java index ea6eeb102c..bf3924b70b 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java @@ -53,6 +53,7 @@ import org.kohsuke.args4j.Option; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler; +import org.eclipse.jgit.revwalk.FollowFilter; import org.eclipse.jgit.revwalk.ObjectWalk; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevFlag; @@ -110,11 +111,16 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { enableRevSort(RevSort.BOUNDARY, on); } + @Option(name = "--follow", metaVar = "metaVar_path") + void follow(final String path) { + pathFilter = FollowFilter.create(path); + } + @Argument(index = 0, metaVar = "metaVar_commitish") private final List<RevCommit> commits = new ArrayList<RevCommit>(); @Option(name = "--", metaVar = "metaVar_path", multiValued = true, handler = PathTreeFilterHandler.class) - private TreeFilter pathFilter = TreeFilter.ALL; + protected TreeFilter pathFilter = TreeFilter.ALL; private final List<RevFilter> revLimiter = new ArrayList<RevFilter>(); @@ -139,7 +145,9 @@ abstract class RevWalkTextBuiltin extends TextBuiltin { for (final RevSort s : sorting) walk.sort(s, true); - if (pathFilter != TreeFilter.ALL) + if (pathFilter instanceof FollowFilter) + walk.setTreeFilter(pathFilter); + else if (pathFilter != TreeFilter.ALL) walk.setTreeFilter(AndTreeFilter.create(pathFilter, TreeFilter.ANY_DIFF)); |