diff options
author | Andre Bossert <andre.bossert@siemens.com> | 2020-01-19 20:54:17 +0100 |
---|---|---|
committer | Andrey Loskutov <loskutov@gmx.de> | 2022-05-30 13:28:32 +0200 |
commit | e81085944f1a039566f2972c863d189724988b46 (patch) | |
tree | b56edc0b3da0259178dd90c03755f0869c94e31e /org.eclipse.jgit.pgm | |
parent | d128c3112d76960c63a5b4df54246671c6ea5a33 (diff) | |
download | jgit-e81085944f1a039566f2972c863d189724988b46.tar.gz jgit-e81085944f1a039566f2972c863d189724988b46.zip |
Add filtering with help of DirCacheCheckout.getContent()
see: https://git-scm.com/docs/git-mergetool
* refactoring of content (FileElement) handling
* now the temporary files are already filled with filtered content in
the calling classes (PGM), that can be used with EGit content too
TODO:
* keep the temporaries when no change detected and the user answers no
to the question if the merge was successful
Bug: 356832
Change-Id: I86a0a052d059957d4d152c1bb94c262902c377d2
Signed-off-by: Andre Bossert <andre.bossert@siemens.com>
Diffstat (limited to 'org.eclipse.jgit.pgm')
-rw-r--r-- | org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java | 94 | ||||
-rw-r--r-- | org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java | 85 |
2 files changed, 133 insertions, 46 deletions
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java index ffba36fe20..74d91cd3d7 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java @@ -11,9 +11,11 @@ package org.eclipse.jgit.pgm; import static org.eclipse.jgit.lib.Constants.HEAD; +import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP; import java.io.BufferedOutputStream; import java.io.BufferedReader; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; @@ -25,27 +27,36 @@ import org.eclipse.jgit.diff.ContentSource; import org.eclipse.jgit.diff.ContentSource.Pair; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffEntry.Side; +import org.eclipse.jgit.internal.diffmergetool.ToolException; +import org.eclipse.jgit.internal.diffmergetool.DiffTools; +import org.eclipse.jgit.internal.diffmergetool.FileElement; +import org.eclipse.jgit.internal.diffmergetool.ExternalDiffTool; import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.dircache.DirCacheCheckout; import org.eclipse.jgit.dircache.DirCacheIterator; +import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata; import org.eclipse.jgit.errors.AmbiguousObjectException; +import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.errors.RevisionSyntaxException; -import org.eclipse.jgit.internal.diffmergetool.DiffTools; -import org.eclipse.jgit.internal.diffmergetool.ExternalDiffTool; -import org.eclipse.jgit.internal.diffmergetool.FileElement; -import org.eclipse.jgit.internal.diffmergetool.ToolException; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; -import org.eclipse.jgit.lib.ObjectStream; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.TextProgressMonitor; +import org.eclipse.jgit.lib.CoreConfig.EolStreamType; import org.eclipse.jgit.lib.internal.BooleanTriState; import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler; +import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.FileTreeIterator; +import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.WorkingTreeIterator; +import org.eclipse.jgit.treewalk.WorkingTreeOptions; +import org.eclipse.jgit.treewalk.filter.PathFilterGroup; import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.jgit.util.StringUtils; import org.eclipse.jgit.util.FS.ExecutionResult; @@ -164,12 +175,6 @@ class DiffTool extends TextBuiltin { if (mergedFilePath.equals(DiffEntry.DEV_NULL)) { mergedFilePath = ent.getOldPath(); } - FileElement local = new FileElement(ent.getOldPath(), - ent.getOldId().name(), - getObjectStream(sourcePair, Side.OLD, ent)); - FileElement remote = new FileElement(ent.getNewPath(), - ent.getNewId().name(), - getObjectStream(sourcePair, Side.NEW, ent)); // check if user wants to launch compare boolean launchCompare = true; if (showPrompt) { @@ -178,15 +183,20 @@ class DiffTool extends TextBuiltin { } if (launchCompare) { try { - // TODO: check how to return the exit-code of - // the - // tool - // to - // jgit / java runtime ? + FileElement local = createFileElement( + FileElement.Type.LOCAL, sourcePair, Side.OLD, + ent); + FileElement remote = createFileElement( + FileElement.Type.REMOTE, sourcePair, Side.NEW, + ent); + FileElement merged = new FileElement(mergedFilePath, + FileElement.Type.MERGED); + // TODO: check how to return the exit-code of the tool + // to jgit / java runtime ? // int rc =... - ExecutionResult result = diffTools.compare(db, local, - remote, mergedFilePath, - toolName, prompt, gui, trustExitCode); + ExecutionResult result = diffTools.compare(local, + remote, merged, toolName, prompt, gui, + trustExitCode); outw.println(new String(result.getStdout().toByteArray())); errw.println( new String(result.getStderr().toByteArray())); @@ -278,16 +288,46 @@ class DiffTool extends TextBuiltin { return files; } - private ObjectStream getObjectStream(Pair pair, Side side, DiffEntry ent) { - ObjectStream stream = null; - if (!pair.isWorkingTreeSource(side)) { - try { - stream = pair.open(side, ent).openStream(); - } catch (Exception e) { - stream = null; + private FileElement createFileElement(FileElement.Type elementType, + Pair pair, Side side, DiffEntry entry) + throws NoWorkTreeException, CorruptObjectException, IOException, + ToolException { + String entryPath = side == Side.NEW ? entry.getNewPath() + : entry.getOldPath(); + FileElement fileElement = new FileElement(entryPath, elementType); + if (!pair.isWorkingTreeSource(side) && !fileElement.isNullPath()) { + try (RevWalk revWalk = new RevWalk(db); + TreeWalk treeWalk = new TreeWalk(db, + revWalk.getObjectReader())) { + treeWalk.setFilter( + PathFilterGroup.createFromStrings(entryPath)); + if (side == Side.NEW) { + newTree.reset(); + treeWalk.addTree(newTree); + } else { + oldTree.reset(); + treeWalk.addTree(oldTree); + } + if (treeWalk.next()) { + final EolStreamType eolStreamType = treeWalk + .getEolStreamType(CHECKOUT_OP); + final String filterCommand = treeWalk.getFilterCommand( + Constants.ATTR_FILTER_TYPE_SMUDGE); + WorkingTreeOptions opt = db.getConfig() + .get(WorkingTreeOptions.KEY); + CheckoutMetadata checkoutMetadata = new CheckoutMetadata( + eolStreamType, filterCommand); + DirCacheCheckout.getContent(db, entryPath, + checkoutMetadata, pair.open(side, entry), opt, + new FileOutputStream( + fileElement.createTempFile(null))); + } else { + throw new ToolException("Cannot find path '" + entryPath //$NON-NLS-1$ + + "' in staging area!", null); //$NON-NLS-1$ + } } } - return stream; + return fileElement; } private ContentSource source(AbstractTreeIterator iterator) { diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java index dce5a7996d..9712770758 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java @@ -10,8 +10,11 @@ package org.eclipse.jgit.pgm; +import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP; + import java.io.BufferedReader; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.text.MessageFormat; @@ -26,8 +29,12 @@ import org.eclipse.jgit.api.Status; import org.eclipse.jgit.api.StatusCommand; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.diff.ContentSource; +import org.eclipse.jgit.internal.diffmergetool.FileElement.Type; import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheCheckout; import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.dircache.DirCacheIterator; +import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.errors.RevisionSyntaxException; import org.eclipse.jgit.internal.diffmergetool.ExternalMergeTool; @@ -35,9 +42,15 @@ import org.eclipse.jgit.internal.diffmergetool.FileElement; import org.eclipse.jgit.internal.diffmergetool.MergeTools; import org.eclipse.jgit.internal.diffmergetool.ToolException; import org.eclipse.jgit.lib.IndexDiff.StageState; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.WorkingTreeOptions; +import org.eclipse.jgit.treewalk.filter.PathFilterGroup; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.internal.BooleanTriState; +import org.eclipse.jgit.lib.CoreConfig.EolStreamType; import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.util.FS.ExecutionResult; import org.kohsuke.args4j.Argument; @@ -188,32 +201,67 @@ class MergeTool extends TextBuiltin { ContentSource baseSource = ContentSource.create(db.newObjectReader()); ContentSource localSource = ContentSource.create(db.newObjectReader()); ContentSource remoteSource = ContentSource.create(db.newObjectReader()); + // temporary directory if mergetool.writeToTemp == true + File tempDir = mergeTools.createTempDirectory(); + // the parent directory for temp files (can be same as tempDir or just + // the worktree dir) + File tempFilesParent = tempDir != null ? tempDir : db.getWorkTree(); try { FileElement base = null; FileElement local = null; FileElement remote = null; + FileElement merged = new FileElement(mergedFilePath, + Type.MERGED); DirCache cache = db.readDirCache(); - int firstIndex = cache.findEntry(mergedFilePath); - if (firstIndex >= 0) { - int nextIndex = cache.nextEntry(firstIndex); - for (; firstIndex < nextIndex; firstIndex++) { - DirCacheEntry entry = cache.getEntry(firstIndex); + try (RevWalk revWalk = new RevWalk(db); + TreeWalk treeWalk = new TreeWalk(db, + revWalk.getObjectReader())) { + treeWalk.setFilter( + PathFilterGroup.createFromStrings(mergedFilePath)); + DirCacheIterator cacheIter = new DirCacheIterator(cache); + treeWalk.addTree(cacheIter); + while (treeWalk.next()) { + if (treeWalk.isSubtree()) { + treeWalk.enterSubtree(); + continue; + } + final EolStreamType eolStreamType = treeWalk + .getEolStreamType(CHECKOUT_OP); + final String filterCommand = treeWalk.getFilterCommand( + Constants.ATTR_FILTER_TYPE_SMUDGE); + WorkingTreeOptions opt = db.getConfig() + .get(WorkingTreeOptions.KEY); + CheckoutMetadata checkoutMetadata = new CheckoutMetadata( + eolStreamType, filterCommand); + DirCacheEntry entry = treeWalk.getTree(DirCacheIterator.class).getDirCacheEntry(); + if (entry == null) { + continue; + } ObjectId id = entry.getObjectId(); switch (entry.getStage()) { case DirCacheEntry.STAGE_1: - base = new FileElement(mergedFilePath, id.name(), - baseSource.open(mergedFilePath, id) - .openStream()); + base = new FileElement(mergedFilePath, Type.BASE); + DirCacheCheckout.getContent(db, mergedFilePath, + checkoutMetadata, + baseSource.open(mergedFilePath, id), opt, + new FileOutputStream( + base.createTempFile(tempFilesParent))); break; case DirCacheEntry.STAGE_2: - local = new FileElement(mergedFilePath, id.name(), - localSource.open(mergedFilePath, id) - .openStream()); + local = new FileElement(mergedFilePath, Type.LOCAL); + DirCacheCheckout.getContent(db, mergedFilePath, + checkoutMetadata, + localSource.open(mergedFilePath, id), opt, + new FileOutputStream( + local.createTempFile(tempFilesParent))); break; case DirCacheEntry.STAGE_3: - remote = new FileElement(mergedFilePath, id.name(), - remoteSource.open(mergedFilePath, id) - .openStream()); + remote = new FileElement(mergedFilePath, Type.REMOTE); + DirCacheCheckout.getContent(db, mergedFilePath, + checkoutMetadata, + remoteSource.open(mergedFilePath, id), opt, + new FileOutputStream(remote + .createTempFile(tempFilesParent))); break; } } @@ -222,14 +270,13 @@ class MergeTool extends TextBuiltin { throw die(MessageFormat.format(CLIText.get().mergeToolDied, mergedFilePath)); } - File merged = new File(mergedFilePath); - long modifiedBefore = merged.lastModified(); + long modifiedBefore = merged.getFile().lastModified(); try { // TODO: check how to return the exit-code of the // tool to jgit / java runtime ? // int rc =... - ExecutionResult executionResult = mergeTools.merge(db, local, - remote, base, mergedFilePath, toolName, prompt, gui); + ExecutionResult executionResult = mergeTools.merge(local, + remote, merged, base, tempDir, toolName, prompt, gui); outw.println( new String(executionResult.getStdout().toByteArray())); outw.flush(); @@ -250,7 +297,7 @@ class MergeTool extends TextBuiltin { } // if merge was successful check file modified if (isMergeSuccessful) { - long modifiedAfter = merged.lastModified(); + long modifiedAfter = merged.getFile().lastModified(); if (modifiedBefore == modifiedAfter) { outw.println(MessageFormat.format( CLIText.get().mergeToolFileUnchanged, |