Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 20df86e70ee8f50e1888db17f12d31e5527631d1 (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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/*******************************************************************************
 * Copyright (c) 2000, 2009 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.team.core.mapping;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.team.core.diff.IDiff;
import org.eclipse.team.core.diff.IDiffChangeListener;
import org.eclipse.team.core.diff.IDiffTree;
import org.eclipse.team.core.diff.IThreeWayDiff;
import org.eclipse.team.core.diff.ITwoWayDiff;
import org.eclipse.team.core.mapping.provider.MergeContext;

/**
 * Provides the context for an <code>IResourceMappingMerger</code> or a model
 * specific synchronization view that supports merging.
 * <p>
 * The diff tree associated with this context may be updated asynchronously in
 * response to calls to any method of this context (e.g. merge and markAsMerged
 * methods) that may result in changes in the synchronization state of
 * resources. It may also get updated as a result of changes triggered from
 * other sources. Hence, the callback from the diff tree to report changes may
 * occur in the same thread as the method call or asynchronously in a separate
 * thread, regardless of who triggered the refresh. Clients of this method (and
 * any other asynchronous method on this context) may determine if all changes
 * have been collected using {@link IJobManager#find(Object)} using this context
 * as the <code>family</code> argument in order to determine if there are any
 * jobs running that are populating the diff tree. Clients may also call
 * {@link IJobManager#join(Object, IProgressMonitor)} if they wish to wait until
 * all background handlers related to this context are finished.
 * </p>
 *
 * @see IResourceMappingMerger
 * @see MergeContext
 * @since 3.2
 * @noimplement This interface is not intended to be implemented by clients.
 *              Clients should instead subclass {@link MergeContext}.
 */
public interface IMergeContext extends ISynchronizationContext {

	/**
	 * Return the type of merge that will be performed when using this
	 * context (either {@link ISynchronizationContext#TWO_WAY} or
	 * {@link ISynchronizationContext#THREE_WAY}). In most cases,
	 * this type which match that returned by {@link ISynchronizationContext#getType()}.
	 * However, for some THREE_WAY synchronizations, the merge type may
	 * be TWO_WAY which indicates that clients of the context should
	 * ignore local changes when performing merges. This capability is
	 * provided to support replace operations that support three-way
	 * preview but ignore local changes when replacing.
	 * @return the type of merge that will be performed when using this
	 * context.
	 */
	public int getMergeType();

	/**
	 * Method that allows the model merger to signal that the file associated
	 * with the given diff node has been completely merged. Model mergers can
	 * call this method if they have transfered all changes from a remote file
	 * to a local file and wish to signal that the merge is done. This will
	 * allow repository providers to update the synchronization state of the
	 * file to reflect that the file is up-to-date with the repository.
	 * <p>
	 * For two-way merging, this method can be used to reject any change. For
	 * three-way merging, this method should only be used when remote content in
	 * being merged with local content (i.e. the file exists both locally and
	 * remotely) with the exception that it can also be used to keep local
	 * changes to a file that has been deleted. See the
	 * {@link #merge(IDiff[], boolean, IProgressMonitor) } method for more
	 * details. For other cases in which either the local file or remote file
	 * does not exist, one of the <code>merge</code> methods should be used.
	 * This is done to accommodate repositories that have special handling for
	 * file additions, removals and moves. Invoking this method with a diff node
	 * associated with a folder will have no effect.
	 * <p>
	 * The <code>inSyncHint</code> allows a client to indicate to the context
	 * that the model persisted in the file is in-sync. If the hint is
	 * <code>true</code>, the context should compare the local and remote
	 * file at the content level and make the local file in-sync with the remote
	 * if the contents are the same.
	 * </p>
	 *
	 * @param node the diff node whose file has been merged
	 * @param inSyncHint a hint to the context that the model persisted in the
	 *            file is in-sync.
	 * @param monitor a progress monitor
	 * @throws CoreException if errors occur
	 */
	public void markAsMerged(IDiff node, boolean inSyncHint,
			IProgressMonitor monitor) throws CoreException;

	/**
	 * Mark the files associated with the given diff nodes as being merged.
	 * This method is equivalent to calling {@link #markAsMerged(IDiff, boolean, IProgressMonitor) }
	 * for each diff but gives the context the opportunity to optimize the
	 * operation for multiple files.
	 * <p>
	 * This method will batch change notification by using the
	 * {@link #run(IWorkspaceRunnable, ISchedulingRule, int, IProgressMonitor) }
	 * method. The rule for he method will be obtained using
	 * {@link #getMergeRule(IDiff)} and the flags will be
	 * <code>IResource.NONE</code> meaning that intermittent change events may
	 * occur. Clients may wrap the call in an outer run that either uses a
	 * broader scheduling rule or the <code>IWorkspace.AVOID_UPDATES</code>
	 * flag.
	 *
	 * @param nodes the nodes to be marked as merged
	 * @param inSyncHint a hint to the context that the model persisted in the
	 *            file is in-sync.
	 * @param monitor a progress monitor
	 * @throws CoreException if errors occur
	 */
	public void markAsMerged(IDiff[] nodes, boolean inSyncHint,
			IProgressMonitor monitor) throws CoreException;

	/**
	 * Method that can be called by the model merger to attempt a file-system
	 * level merge. This is useful for cases where the model merger does not
	 * need to do any special processing to perform the merge. By default, this
	 * method attempts to use an appropriate {@link IStorageMerger} to merge the
	 * files covered by the provided traversals. If a storage merger cannot be
	 * found, the text merger is used. If this behavior is not desired,
	 * sub-classes of {@link MergeContext} may override this method.
	 * <p>
	 * This method does a best-effort attempt to merge of the file associated
	 * with the given diff. A file that could not be merged will be indicated in
	 * the returned status. If the status returned has the code
	 * <code>MergeStatus.CONFLICTS</code>, the list of failed files can be
	 * obtained by calling the <code>MergeStatus#getConflictingFiles()</code>
	 * method.
	 * <p>
	 * It is not expected that clients of this API will associate special
	 * meaning with the existence of a folder other than the fact that it
	 * contains files. The sync delta tree should still include folder changes
	 * so that clients that have a one-to-one correspondence between their model
	 * objects and folders can decorate these elements appropriately. However,
	 * clients of this API will only be expected to perform operations on file
	 * deltas and will expect folders to be created as needed to contain the
	 * files (i.e. implementations of this method should ignore any folder
	 * deltas in the provided deltas). Clients will also expect local folders
	 * that have incoming folder deletions to be removed once all the folder's
	 * children have been removed using merge.
	 * <p>
	 * There are two special cases where merge is meaningful for folders. First,
	 * a merge on a local added empty folder with force set should delete the
	 * folder. However, the folder should not be deleted if it has any local
	 * children unless merge is called for those resources first and they end up
	 * being deleted as a result. Second, a merge on an incoming folder addition
	 * should create the empty folder locally.
	 * <p>
	 * It is not expected that clients of this API will be capable of dealing
	 * with namespace conflicts. Implementors should ensure that any namespace
	 * conflicts are dealt with before the merger is invoked.
	 * <p>
	 * The deltas provided to this method should be those obtained from the tree ({@link ISynchronizationContext#getDiffTree()})
	 * of this context. Any resource changes triggered by this merge will be
	 * reported through the resource delta mechanism and the change notification
	 * mechanisms of the delta tree associated with this context.
	 * <p>
	 * For two-way merging, as indicated by either the
	 * {@link ISynchronizationContext#getType()} or {@link #getMergeType()}
	 * methods, clients can either accept changes using the
	 * {@link #merge(IDiff[], boolean, IProgressMonitor) } method or reject them
	 * using {@link #markAsMerged(IDiff, boolean, IProgressMonitor) }.
	 * Three-way changes are a bit more complicated. The following list
	 * summarizes how particular remote file changes can be handled. The delta
	 * kind and flags mentioned in the descriptions are obtained the remote
	 * change (see {@link IThreeWayDiff#getRemoteChange()}), whereas conflicts
	 * are indicated by the three-way delta itself.
	 * <ul>
	 *
	 * <li> When the delta kind is {@link IDiff#ADD} and the delta is also a
	 * move (i.e. the {@link ITwoWayDiff#MOVE_FROM} is set). The merge can
	 * either use the {@link #merge(IDiff[], boolean, IProgressMonitor) } method
	 * to accept the rename or perform an
	 * {@link IFile#move(IPath, boolean, boolean, IProgressMonitor) } where the
	 * source file is obtained using {@link ITwoWayDiff#getFromPath()} and the
	 * destination is the path of the delta ({@link IDiff#getPath()}). This
	 * later approach is helpful in the case where the local file and remote
	 * file both contain content changes (i.e. the file can be moved by the
	 * model and then the contents can be merged by the model). </li>
	 *
	 * <li> When the delta kind is {@link IDiff#REMOVE} and the delta is also a
	 * move (i.e. the {@link ITwoWayDiff#MOVE_TO} is set). The merge can either
	 * use the {@link #merge(IDiff[], boolean, IProgressMonitor) } method to
	 * accept the rename or perform an
	 * {@link IFile#move(IPath, boolean, boolean, IProgressMonitor) } where the
	 * source file is obtained using {@link IDiff#getPath()} and the destination
	 * is obtained from {@link ITwoWayDiff#getToPath()}. This later approach is
	 * helpful in the case where the local file and remote file both contain
	 * content changes (i.e. the file can be moved by the model and then the
	 * contents can be merged by the model). </li>
	 *
	 * <li> When the delta kind is {@link IDiff#ADD} and it is not part of a
	 * move, the merger must use the
	 * {@link #merge(IDiff[], boolean, IProgressMonitor) } method to accept this
	 * change. If there is a conflicting addition, the force flag can be set to
	 * override the local change. If the model wishes to keep the local changes,
	 * they can overwrite the file after merging it. Models should consult the
	 * flags to see if the remote change is a rename ({@link ITwoWayDiff#MOVE_FROM}).
	 * </li>
	 *
	 * <li>When the delta kind is {@link IDiff#REMOVE} and it is not part of a
	 * move, the merger can use the
	 * {@link #merge(IDiff[], boolean, IProgressMonitor) } method but could also
	 * perform the delete manually using any of the {@link IFile} delete
	 * methods. In the case where there are local changes to the file being
	 * deleted, the model may either choose to merge using the force flag (thus
	 * removing the file and the local changes) or call
	 * {@link #markAsMerged(IDiff, boolean, IProgressMonitor) } on the file
	 * which will convert the incoming deletion to an outgoing addition.</li>
	 *
	 * <li>When the delta kind is {@link IDiff#CHANGE} and there is no
	 * conflict, the model is advised to use the
	 * {@link #merge(IDiff[], boolean, IProgressMonitor) } method to merge these
	 * changes as this is the most efficient means to do so. However, the model
	 * can choose to perform the merge themselves and then invoke
	 * {@link #markAsMerged(IDiff, boolean, IProgressMonitor) } with the
	 * <code>inSyncHint</code> set to <code>true</code> but this will be
	 * less efficient. </li>
	 *
	 * <li>When the delta kind is {@link IDiff#CHANGE} and there is a conflict,
	 * the model can use the {@link #merge(IDiff[], boolean, IProgressMonitor) }
	 * method to merge these changes. If the force flag is not set, an
	 * auto-merge is attempted using an appropriate {@link IStorageMerger}. If
	 * the force flag is set, the local changes are discarded. The model can
	 * choose to attempt the merge themselves and, if it is successful, invoke
	 * {@link #markAsMerged(IDiff, boolean, IProgressMonitor) } with the
	 * <code>inSyncHint</code> set to <code>false</code> which will make the
	 * file an outgoing change. </li>
	 * </ul>
	 *
	 * TODO: need to talk about ITwoWayDelta CONTENT and REPLACED
	 *
	 * @see IDiffTree#addDiffChangeListener(IDiffChangeListener)
	 * @see org.eclipse.core.resources.IWorkspace#addResourceChangeListener(IResourceChangeListener)
	 *
	 * @param diff
	 *            the difference to be merged
	 * @param ignoreLocalChanges
	 *            ignore any local changes when performing the merge.
	 * @param monitor
	 *            a progress monitor
	 * @return a status indicating success or failure. A code of
	 *         <code>MergeStatus.CONFLICTS</code> indicates that the file
	 *         contain non-mergable conflicts and must be merged manually.
	 * @throws CoreException
	 *             if an error occurs
	 */
	public IStatus merge(IDiff diff, boolean ignoreLocalChanges, IProgressMonitor monitor)
			throws CoreException;

	/**
	 * Attempt to merge any files associated with the given diffs. This method
	 * is equivalent to calling
	 * {@link #merge(IDiff, boolean, IProgressMonitor) } for each diff
	 * individually but gives the context a chance to perform a more optimal
	 * merge involving multiple resources.
	 * <p>
	 * This method will batch change notification by using the
	 * {@link #run(IWorkspaceRunnable, ISchedulingRule, int, IProgressMonitor) }
	 * method. The rule for he method will be obtained using
	 * {@link #getMergeRule(IDiff) } and the flags will be
	 * <code>IResource.NONE</code> meaning that intermittent change events may
	 * occur. Clients may wrap the call in an outer run that either uses a
	 * broader scheduling rule or the <code>IWorkspace.AVOID_UPDATES</code>
	 * flag.
	 *
	 * @param diffs the differences to be merged
	 * @param ignoreLocalChanges ignore any local changes when performing the merge.
	 * @param monitor a progress monitor
	 * @return a status indicating success or failure. A code of
	 *         <code>MergeStatus.CONFLICTS</code> indicates that the file
	 *         contain non-mergable conflicts and must be merged manually.
	 * @throws CoreException if an error occurs
	 */
	public IStatus merge(IDiff[] diffs, boolean ignoreLocalChanges,
			IProgressMonitor monitor) throws CoreException;

	/**
	 * Reject the change associated with the given diff. For a two-way
	 * merge, this should just remove the change from the set of changes in
	 * the diff tree. For a three-way merge, this should throw away the
	 * remote change and keep any local changes. So, for instance, if
	 * the diff is an incoming change or a conflict, the result of rejecting the
	 * change should be an outgoing change that will make the remote state
	 * match the local state.
	 * @param diff the diff
	 * @param monitor a progress monitor
	 * @throws CoreException if an error occurs
	 */
	public void reject(IDiff diff, IProgressMonitor monitor) throws CoreException;

	/**
	 * Reject the changes associated with the given diffs. This method is
	 * equivalent to calling {@link #reject(IDiff, IProgressMonitor)} for
	 * each diff.
	 * @param diffs the diffs
	 * @param monitor a progress monitor
	 * @throws CoreException if an error occurs
	 */
	public void reject(IDiff[] diffs, IProgressMonitor monitor) throws CoreException;

	/**
	 * Runs the given action as an atomic workspace operation. It has the same
	 * semantics as
	 * {@link IWorkspace#run(IWorkspaceRunnable, ISchedulingRule, int, IProgressMonitor)}
	 * with the added behavior that any synchronization state updates are
	 * batched or deferred until the end of the operation (depending on the
	 * {@link IWorkspace#AVOID_UPDATE } flag.
	 *
	 * @param runnable a workspace runnable
	 * @param rule a scheduling rule to be obtained while the runnable is run
	 * @param flags flags indicating when updates occur (either
	 *            <code>IResource.NONE</code> or
	 *            <code>IWorkspace.AVOID_UPDATE</code>.
	 * @param monitor a progress monitor
	 * @throws CoreException if an error occurs
	 */
	public void run(IWorkspaceRunnable runnable, ISchedulingRule rule,
			int flags, IProgressMonitor monitor) throws CoreException;

	/**
	 * Return the scheduling rule that is required to merge (or reject) the resource
	 * associated with the given diff. If a resource being merged is a folder or
	 * project, the returned rule will be sufficient to merge any files
	 * contained in the folder or project. The returned rule also applies to
	 * {@link #markAsMerged(IDiff, boolean, IProgressMonitor) }
	 * and {@link #reject(IDiff, IProgressMonitor)}.
	 *
	 * @param diff the diff to be merged
	 * @return the scheduling rule that is required to merge the resource of the
	 *         given diff
	 */
	public ISchedulingRule getMergeRule(IDiff diff);

	/**
	 * Return the scheduling rule that is required to merge (or reject) the resources
	 * associated with the given diffs. If a resource being merged is a folder
	 * or project, the returned rule will be sufficient to merge any files
	 * contained in the folder or project. The returned rule also applies to
	 * {@link #markAsMerged(IDiff[], boolean, IProgressMonitor) }
	 * and {@link #reject(IDiff[], IProgressMonitor)}.
	 *
	 * @param diffs the diffs being merged
	 * @return the scheduling rule that is required to merge the resources of
	 *         the given diffs
	 */
	public ISchedulingRule getMergeRule(IDiff[] diffs);

}

Back to the top