blob: 4160b131fcadfa801efd8f72972f74f4e1de2c77 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2011 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.compare.internal.core.patch;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.compare.patch.IFilePatch2;
import org.eclipse.compare.patch.IFilePatchResult;
import org.eclipse.compare.patch.IHunk;
import org.eclipse.compare.patch.PatchConfiguration;
import org.eclipse.compare.patch.ReaderCreator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
/**
* A file diff represents a set of hunks that were associated with the
* same path in a patch file.
*/
public class FilePatch2 implements IFilePatch2 {
/**
* Difference constant (value 1) indicating one side was added.
*/
public static final int ADDITION= 1;
/**
* Difference constant (value 2) indicating one side was removed.
*/
public static final int DELETION= 2;
/**
* Difference constant (value 3) indicating side changed.
*/
public static final int CHANGE= 3;
private IPath fOldPath, fNewPath;
private long oldDate, newDate;
private List<Hunk> fHunks= new ArrayList<>();
private DiffProject fProject; //the project that contains this diff
private String header;
private int addedLines, removedLines;
/**
* Create a file diff for the given path and date information.
* @param oldPath the path of the before state of the file
* @param oldDate the timestamp of the before state
* @param newPath the path of the after state
* @param newDate the timestamp of the after state
*/
public FilePatch2(IPath oldPath, long oldDate, IPath newPath, long newDate) {
this.fOldPath= oldPath;
this.oldDate = oldDate;
this.fNewPath= newPath;
this.newDate = newDate;
}
/**
* Return the parent project or <code>null</code> if there isn't one.
* @return the parent project or <code>null</code>
*/
public DiffProject getProject() {
return this.fProject;
}
/**
* Set the project of this diff to the given project.
* This method should only be called from
* {@link DiffProject#add(FilePatch2)}
* @param diffProject the parent project
*/
void setProject(DiffProject diffProject) {
if (this.fProject == diffProject)
return;
if (this.fProject != null)
this.fProject.remove(this);
this.fProject= diffProject;
}
/**
* Get the path of the file diff.
* @param reverse whether the path of the before state or after state
* should be used
* @return the path of the file diff
*/
public IPath getPath(boolean reverse) {
if (getDiffType(reverse) == ADDITION) {
if (reverse)
return this.fOldPath;
return this.fNewPath;
}
if (reverse && this.fNewPath != null)
return this.fNewPath;
if (this.fOldPath != null)
return this.fOldPath;
return this.fNewPath;
}
/**
* Add the hunk to this file diff.
* @param hunk the hunk
*/
public void add(Hunk hunk) {
this.fHunks.add(hunk);
hunk.setParent(this);
}
/**
* Remove the hunk from this file diff
* @param hunk the hunk
*/
protected void remove(Hunk hunk) {
this.fHunks.remove(hunk);
}
/**
* Returns the hunks associated with this file diff.
* @return the hunks associated with this file diff
*/
@Override
public IHunk[] getHunks() {
return this.fHunks.toArray(new IHunk[this.fHunks.size()]);
}
/**
* Returns the number of hunks associated with this file diff.
* @return the number of hunks associated with this file diff
*/
public int getHunkCount() {
return this.fHunks.size();
}
/**
* Returns the difference type of this file diff.
* @param reverse whether the patch is being reversed
* @return the type of this file diff
*/
public int getDiffType(boolean reverse) {
if (this.fHunks.size() == 1) {
boolean add = false;
boolean delete = false;
Iterator<Hunk> iter = this.fHunks.iterator();
while (iter.hasNext()){
Hunk hunk = iter.next();
int type =hunk.getHunkType(reverse);
if (type == ADDITION){
add = true;
} else if (type == DELETION ){
delete = true;
}
}
if (add && !delete){
return ADDITION;
} else if (!add && delete){
return DELETION;
}
}
return CHANGE;
}
/**
* Return the path of this file diff with the specified number
* of leading segments striped.
* @param strip the number of leading segments to strip from the path
* @param reverse whether the patch is being reversed
* @return the path of this file diff with the specified number
* of leading segments striped
*/
public IPath getStrippedPath(int strip, boolean reverse) {
IPath path= getPath(reverse);
if (strip > 0 && strip < path.segmentCount())
path= path.removeFirstSegments(strip);
return path;
}
/**
* Return the segment count of the path of this file diff.
* @return the segment count of the path of this file diff
*/
public int segmentCount() {
//Update prefix count - go through all of the diffs and find the smallest
//path segment contained in all diffs.
int length= 99;
if (this.fOldPath != null)
length= Math.min(length, this.fOldPath.segmentCount());
if (this.fNewPath != null)
length= Math.min(length, this.fNewPath.segmentCount());
return length;
}
@Override
public IFilePatchResult apply(ReaderCreator content,
PatchConfiguration configuration, IProgressMonitor monitor) {
FileDiffResult result = new FileDiffResult(this, configuration);
result.refresh(content, monitor);
return result;
}
@Override
public IPath getTargetPath(PatchConfiguration configuration) {
return getStrippedPath(configuration.getPrefixSegmentStripCount(), configuration.isReversed());
}
public FilePatch2 asRelativeDiff() {
if (this.fProject == null)
return this;
IPath adjustedOldPath = null;
if (this.fOldPath != null) {
adjustedOldPath = new Path(null, this.fProject.getName()).append(this.fOldPath);
}
IPath adjustedNewPath = null;
if (this.fNewPath != null) {
adjustedNewPath = new Path(null, this.fProject.getName()).append(this.fNewPath);
}
FilePatch2 diff = create(adjustedOldPath, 0, adjustedNewPath, 0);
for (Iterator<Hunk> iterator = this.fHunks.iterator(); iterator.hasNext();) {
Hunk hunk = iterator.next();
// Creating the hunk adds it to the parent diff
new Hunk(diff, hunk);
}
return diff;
}
protected FilePatch2 create(IPath oldPath, long oldDate, IPath newPath,
long newDate) {
return new FilePatch2(oldPath, oldDate, newPath, newDate);
}
public void setHeader(String header) {
this.header = header;
}
@Override
public String getHeader() {
return this.header;
}
@Override
public long getBeforeDate() {
return this.oldDate;
}
@Override
public long getAfterDate() {
return this.newDate;
}
public void setAddedLines(int addedLines) {
this.addedLines = addedLines;
}
public void setRemovedLines(int removedLines) {
this.removedLines = removedLines;
}
public int getAddedLines() {
return this.addedLines;
}
public int getRemovedLines() {
return this.removedLines;
}
}