| /* | |
| * Copyright (C) 2011, Tomasz Zarna <Tomasz.Zarna@pl.ibm.com> and others | |
| * | |
| * This program and the accompanying materials are made available under the | |
| * terms of the Eclipse Distribution License v. 1.0 which is available at | |
| * https://www.eclipse.org/org/documents/edl-v10.php. | |
| * | |
| * SPDX-License-Identifier: BSD-3-Clause | |
| */ | |
| package org.eclipse.jgit.api; | |
| import static org.eclipse.jgit.lib.Constants.HEAD; | |
| import java.io.BufferedOutputStream; | |
| import java.io.IOException; | |
| import java.io.OutputStream; | |
| import java.util.List; | |
| import org.eclipse.jgit.api.errors.GitAPIException; | |
| import org.eclipse.jgit.api.errors.JGitInternalException; | |
| import org.eclipse.jgit.api.errors.NoHeadException; | |
| import org.eclipse.jgit.diff.DiffEntry; | |
| import org.eclipse.jgit.diff.DiffFormatter; | |
| import org.eclipse.jgit.dircache.DirCacheIterator; | |
| import org.eclipse.jgit.internal.JGitText; | |
| import org.eclipse.jgit.lib.NullProgressMonitor; | |
| import org.eclipse.jgit.lib.ObjectId; | |
| import org.eclipse.jgit.lib.ObjectReader; | |
| import org.eclipse.jgit.lib.ProgressMonitor; | |
| import org.eclipse.jgit.lib.Repository; | |
| import org.eclipse.jgit.treewalk.AbstractTreeIterator; | |
| import org.eclipse.jgit.treewalk.CanonicalTreeParser; | |
| import org.eclipse.jgit.treewalk.FileTreeIterator; | |
| import org.eclipse.jgit.treewalk.filter.TreeFilter; | |
| import org.eclipse.jgit.util.io.NullOutputStream; | |
| /** | |
| * Show changes between commits, commit and working tree, etc. | |
| * | |
| * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-diff.html" | |
| * >Git documentation about diff</a> | |
| */ | |
| public class DiffCommand extends GitCommand<List<DiffEntry>> { | |
| private AbstractTreeIterator oldTree; | |
| private AbstractTreeIterator newTree; | |
| private boolean cached; | |
| private TreeFilter pathFilter = TreeFilter.ALL; | |
| private boolean showNameAndStatusOnly; | |
| private boolean showNameOnly; | |
| private OutputStream out; | |
| private int contextLines = -1; | |
| private String sourcePrefix; | |
| private String destinationPrefix; | |
| private ProgressMonitor monitor = NullProgressMonitor.INSTANCE; | |
| /** | |
| * Constructor for DiffCommand | |
| * | |
| * @param repo | |
| * a {@link org.eclipse.jgit.lib.Repository} object. | |
| */ | |
| protected DiffCommand(Repository repo) { | |
| super(repo); | |
| } | |
| private DiffFormatter getDiffFormatter() { | |
| return out != null && !showNameAndStatusOnly && !showNameOnly | |
| ? new DiffFormatter(new BufferedOutputStream(out)) | |
| : new DiffFormatter(NullOutputStream.INSTANCE); | |
| } | |
| /** | |
| * {@inheritDoc} | |
| * <p> | |
| * Executes the {@code Diff} command with all the options and parameters | |
| * collected by the setter methods (e.g. {@link #setCached(boolean)} of this | |
| * class. Each instance of this class should only be used for one invocation | |
| * of the command. Don't call this method twice on an instance. | |
| */ | |
| @Override | |
| public List<DiffEntry> call() throws GitAPIException { | |
| try (DiffFormatter diffFmt = getDiffFormatter()) { | |
| diffFmt.setRepository(repo); | |
| diffFmt.setProgressMonitor(monitor); | |
| if (cached) { | |
| if (oldTree == null) { | |
| ObjectId head = repo.resolve(HEAD + "^{tree}"); //$NON-NLS-1$ | |
| if (head == null) | |
| throw new NoHeadException(JGitText.get().cannotReadTree); | |
| CanonicalTreeParser p = new CanonicalTreeParser(); | |
| try (ObjectReader reader = repo.newObjectReader()) { | |
| p.reset(reader, head); | |
| } | |
| oldTree = p; | |
| } | |
| newTree = new DirCacheIterator(repo.readDirCache()); | |
| } else { | |
| if (oldTree == null) { | |
| oldTree = new DirCacheIterator(repo.readDirCache()); | |
| } | |
| if (newTree == null) { | |
| newTree = new FileTreeIterator(repo); | |
| } | |
| } | |
| diffFmt.setPathFilter(pathFilter); | |
| List<DiffEntry> result = diffFmt.scan(oldTree, newTree); | |
| if (showNameAndStatusOnly || showNameOnly) { | |
| return result; | |
| } | |
| if (contextLines >= 0) { | |
| diffFmt.setContext(contextLines); | |
| } | |
| if (destinationPrefix != null) { | |
| diffFmt.setNewPrefix(destinationPrefix); | |
| } | |
| if (sourcePrefix != null) { | |
| diffFmt.setOldPrefix(sourcePrefix); | |
| } | |
| diffFmt.format(result); | |
| diffFmt.flush(); | |
| return result; | |
| } catch (IOException e) { | |
| throw new JGitInternalException(e.getMessage(), e); | |
| } | |
| } | |
| /** | |
| * Whether to view the changes staged for the next commit | |
| * | |
| * @param cached | |
| * whether to view the changes staged for the next commit | |
| * @return this instance | |
| */ | |
| public DiffCommand setCached(boolean cached) { | |
| this.cached = cached; | |
| return this; | |
| } | |
| /** | |
| * Set path filter | |
| * | |
| * @param pathFilter | |
| * parameter, used to limit the diff to the named path | |
| * @return this instance | |
| */ | |
| public DiffCommand setPathFilter(TreeFilter pathFilter) { | |
| this.pathFilter = pathFilter; | |
| return this; | |
| } | |
| /** | |
| * Set old tree | |
| * | |
| * @param oldTree | |
| * the previous state | |
| * @return this instance | |
| */ | |
| public DiffCommand setOldTree(AbstractTreeIterator oldTree) { | |
| this.oldTree = oldTree; | |
| return this; | |
| } | |
| /** | |
| * Set new tree | |
| * | |
| * @param newTree | |
| * the updated state | |
| * @return this instance | |
| */ | |
| public DiffCommand setNewTree(AbstractTreeIterator newTree) { | |
| this.newTree = newTree; | |
| return this; | |
| } | |
| /** | |
| * Set whether to return only names and status of changed files | |
| * | |
| * @param showNameAndStatusOnly | |
| * whether to return only names and status of changed files | |
| * @return this instance | |
| */ | |
| public DiffCommand setShowNameAndStatusOnly(boolean showNameAndStatusOnly) { | |
| this.showNameAndStatusOnly = showNameAndStatusOnly; | |
| return this; | |
| } | |
| /** | |
| * Set whether to return only names of changed files | |
| * | |
| * @param showNameOnly | |
| * whether to return only names files | |
| * @return this instance | |
| * @since 6.4 | |
| */ | |
| public DiffCommand setShowNameOnly(boolean showNameOnly) { | |
| this.showNameOnly = showNameOnly; | |
| return this; | |
| } | |
| /** | |
| * Set output stream | |
| * | |
| * @param out | |
| * the stream to write line data | |
| * @return this instance | |
| */ | |
| public DiffCommand setOutputStream(OutputStream out) { | |
| this.out = out; | |
| return this; | |
| } | |
| /** | |
| * Set number of context lines instead of the usual three. | |
| * | |
| * @param contextLines | |
| * the number of context lines | |
| * @return this instance | |
| */ | |
| public DiffCommand setContextLines(int contextLines) { | |
| this.contextLines = contextLines; | |
| return this; | |
| } | |
| /** | |
| * Set the given source prefix instead of "a/". | |
| * | |
| * @param sourcePrefix | |
| * the prefix | |
| * @return this instance | |
| */ | |
| public DiffCommand setSourcePrefix(String sourcePrefix) { | |
| this.sourcePrefix = sourcePrefix; | |
| return this; | |
| } | |
| /** | |
| * Set the given destination prefix instead of "b/". | |
| * | |
| * @param destinationPrefix | |
| * the prefix | |
| * @return this instance | |
| */ | |
| public DiffCommand setDestinationPrefix(String destinationPrefix) { | |
| this.destinationPrefix = destinationPrefix; | |
| return this; | |
| } | |
| /** | |
| * The progress monitor associated with the diff operation. By default, this | |
| * is set to <code>NullProgressMonitor</code> | |
| * | |
| * @see NullProgressMonitor | |
| * @param monitor | |
| * a progress monitor | |
| * @return this instance | |
| */ | |
| public DiffCommand setProgressMonitor(ProgressMonitor monitor) { | |
| if (monitor == null) { | |
| monitor = NullProgressMonitor.INSTANCE; | |
| } | |
| this.monitor = monitor; | |
| return this; | |
| } | |
| } |