Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 4160b131fcadfa801efd8f72972f74f4e1de2c77 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*******************************************************************************
 * 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;
	}

}

Back to the top