KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > core > CVSSyncInfo


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.team.internal.ccvs.core;
12
13 import org.eclipse.core.resources.*;
14 import org.eclipse.core.runtime.*;
15 import org.eclipse.osgi.util.NLS;
16 import org.eclipse.team.core.TeamException;
17 import org.eclipse.team.core.subscribers.Subscriber;
18 import org.eclipse.team.core.synchronize.SyncInfo;
19 import org.eclipse.team.core.variants.IResourceVariant;
20 import org.eclipse.team.core.variants.ResourceVariantTreeSubscriber;
21 import org.eclipse.team.internal.ccvs.core.client.Update;
22 import org.eclipse.team.internal.ccvs.core.resources.*;
23 import org.eclipse.team.internal.ccvs.core.syncinfo.*;
24 import org.eclipse.team.internal.ccvs.core.util.SyncFileChangeListener;
25
26 /**
27  * CVSSyncInfo
28  */

29 public class CVSSyncInfo extends SyncInfo {
30
31     /*
32      * Codes that are used in returned IStatus
33      */

34     private static final int INVALID_RESOURCE_TYPE = 1;
35     private static final int INVALID_SYNC_KIND = 2;
36     private static final int PARENT_NOT_MANAGED = 3;
37     private static final int REMOTE_DOES_NOT_EXIST = 4;
38     private static final int SYNC_INFO_CONFLICTS = 5;
39     private Subscriber subscriber;
40
41     public CVSSyncInfo(IResource local, IResourceVariant base, IResourceVariant remote, Subscriber subscriber) {
42         super(local, base, remote, ((ResourceVariantTreeSubscriber)subscriber).getResourceComparator());
43         this.subscriber = subscriber;
44     }
45
46     public Subscriber getSubscriber() {
47         return subscriber;
48     }
49     
50     /* (non-Javadoc)
51      * @see org.eclipse.team.core.sync.SyncInfo#computeSyncKind(org.eclipse.core.runtime.IProgressMonitor)
52      */

53     protected int calculateKind() throws TeamException {
54         // special handling for folders, the generic sync algorithm doesn't work well
55
// with CVS because folders are not in namespaces (e.g. they exist in all versions
56
// and branches).
57
IResource local = getLocal();
58         if(local.getType() != IResource.FILE) {
59             int folderKind = SyncInfo.IN_SYNC;
60             ICVSRemoteFolder remote = (ICVSRemoteFolder)getRemote();
61             ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor((IContainer)local);
62             boolean isCVSFolder = false;
63             try {
64                 isCVSFolder = cvsFolder.isCVSFolder();
65             } catch (CVSException e) {
66                 // Assume the folder is not a CVS folder
67
}
68             if(!local.exists()) {
69                 if(remote != null) {
70                     if (isCVSFolder) {
71                         // TODO: This assumes all CVS folders are in-sync even if they have been pruned!
72
folderKind = SyncInfo.IN_SYNC;
73                     } else {
74                         folderKind = SyncInfo.INCOMING | SyncInfo.ADDITION;
75                     }
76                 } else {
77                     // ignore conflicting deletion to keep phantom sync info
78
}
79             } else {
80                 if(remote == null) {
81                     if(isCVSFolder) {
82                         // TODO: This is not really an incoming deletion
83
// The folder will be pruned once any children are commited
84
folderKind = SyncInfo.IN_SYNC;
85                         //folderKind = SyncInfo.INCOMING | SyncInfo.DELETION;
86
} else {
87                         folderKind = SyncInfo.OUTGOING | SyncInfo.ADDITION;
88                     }
89                 } else if(!isCVSFolder) {
90                     folderKind = SyncInfo.CONFLICTING | SyncInfo.ADDITION;
91                 } else {
92                     // folder exists both locally and remotely and are considered in sync, however
93
// we aren't checking the folder mappings to ensure that they are the same.
94
}
95             }
96             return folderKind;
97         }
98     
99         // 1. Run the generic sync calculation algorithm, then handle CVS specific
100
// sync cases.
101
int kind = super.calculateKind();
102     
103         // 2. Set the CVS specific sync type based on the workspace sync state provided
104
// by the CVS server.
105
IResourceVariant remote = getRemote();
106         if(remote!=null && (kind & SyncInfo.PSEUDO_CONFLICT) == 0) {
107             RemoteResource cvsRemote = (RemoteResource)remote;
108             int type = cvsRemote.getWorkspaceSyncState();
109             switch(type) {
110                 // the server compared both text files and decided that it cannot merge
111
// them without line conflicts.
112
case Update.STATE_CONFLICT:
113                     return kind | SyncInfo.MANUAL_CONFLICT;
114
115                 // the server compared both text files and decided that it can safely merge
116
// them without line conflicts.
117
case Update.STATE_MERGEABLE_CONFLICT:
118                     return kind | SyncInfo.AUTOMERGE_CONFLICT;
119             }
120         }
121     
122         // 3. unmanage delete/delete conflicts and return that they are in sync
123
kind = handleDeletionConflicts(kind);
124     
125         return kind;
126     }
127     
128     /*
129      * If the resource has a delete/delete conflict then ensure that the local is unmanaged so that the
130      * sync info can be properly flushed.
131      */

132     protected int handleDeletionConflicts(int kind) {
133         if(kind == (SyncInfo.CONFLICTING | SyncInfo.DELETION | SyncInfo.PSEUDO_CONFLICT)) {
134             try {
135                 IResource local = getLocal();
136                 ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(local);
137                 if(!cvsResource.isFolder() && cvsResource.isManaged()) {
138                     // Reconcile the conflicting deletion in the background
139
SyncFileChangeListener.getDeferredHandler().handleConflictingDeletion(local);
140                 }
141                 return SyncInfo.IN_SYNC;
142             } catch(CVSException e) {
143                 CVSProviderPlugin.log(e);
144                 return SyncInfo.CONFLICTING | SyncInfo.DELETION;
145             }
146         }
147         return kind;
148     }
149
150     /*
151      * Update the sync info of the local resource in such a way that the local changes can be committed.
152      * @return IStatus
153      * For folders, the makeInSYnc method is called and the return codes mentioned there apply
154      * for folders.
155      */

156     public IStatus makeOutgoing(IProgressMonitor monitor) throws TeamException {
157         
158         // For folders, there is no outgoing, only in-sync
159
if (getLocal().getType() == IResource.FOLDER) {
160             return makeInSync();
161         }
162         int syncKind = getKind();
163         boolean incoming = (syncKind & DIRECTION_MASK) == INCOMING;
164         boolean outgoing = (syncKind & DIRECTION_MASK) == OUTGOING;
165
166         ICVSResource local = CVSWorkspaceRoot.getCVSResourceFor(getLocal());
167         RemoteResource remote = (RemoteResource)getRemote();
168         ResourceSyncInfo origInfo = local.getSyncInfo();
169         MutableResourceSyncInfo info = null;
170         if(origInfo!=null) {
171             info = origInfo.cloneMutable();
172         }
173     
174         if (outgoing) {
175                 // The sync info is alright, it's already outgoing!
176
return Status.OK_STATUS;
177         } else if (incoming) {
178             // We have an incoming change, addition, or deletion that we want to ignore
179
if (local.exists()) {
180                 if (remote == null) {
181                     info.setAdded();
182                 } else {
183                     // Otherwise change the revision to the remote revision and dirty the file
184
info.setRevision(remote.getSyncInfo().getRevision());
185                     info.setTimeStamp(null);
186                 }
187             } else {
188                 // We have an incoming add, turn it around as an outgoing delete
189
if (remote == null) {
190                     // Both the local and remote do not exist so clear the sync info
191
info = null;
192                     return Status.OK_STATUS;
193                 } else {
194                     info = remote.getSyncInfo().cloneMutable();
195                     info.setDeleted(true);
196                 }
197             }
198         } else if (local.exists()) {
199             // We have a conflict and a local resource!
200
if (getRemote() != null) {
201                 if (getBase() != null) {
202                     // We have a conflicting change, Update the local revision
203
info.setRevision(remote.getSyncInfo().getRevision());
204                 } else {
205                     try {
206                         // We have conflicting additions.
207
// We need to fetch the contents of the remote to get all the relevant information (timestamp, permissions)
208
// The most important thing we get is the keyword substitution mode which must be right to perform the commit
209
remote.getStorage(Policy.monitorFor(monitor)).getContents();
210                         info = remote.getSyncInfo().cloneMutable();
211                     } catch (CoreException e) {
212                         throw TeamException.asTeamException(e);
213                     }
214                 }
215             } else if (getBase() != null) {
216                 // We have a remote deletion. Make the local an addition
217
info.setAdded();
218             } else {
219                 // There's a local, no base and no remote. We can't possible have a conflict!
220
Assert.isTrue(false);
221             }
222         } else {
223             // We have a conflict and there is no local!
224
if (getRemote() != null) {
225                 // We have a local deletion that conflicts with remote changes.
226
info.setRevision(remote.getSyncInfo().getRevision());
227                 info.setDeleted(true);
228             } else {
229                 // We have conflicting deletions. Clear the sync info
230
info = null;
231                 return Status.OK_STATUS;
232             }
233         }
234         if(info!=null) {
235             FolderSyncInfo parentInfo = local.getParent().getFolderSyncInfo();
236             if (parentInfo == null) {
237                 return new CVSStatus(IStatus.ERROR, PARENT_NOT_MANAGED, NLS.bind(CVSMessages.CVSSyncInfo_9, new String JavaDoc[] { getLocal().getFullPath().toString()}), getLocal());
238             }
239             info.setTag(parentInfo.getTag());
240         }
241         ((ICVSFile)local).setSyncInfo(info, ICVSFile.UNKNOWN);
242         return Status.OK_STATUS;
243     }
244     
245     /*
246      * Load the resource and folder sync info into the local from the remote
247      *
248      * This method can be used on incoming folder additions to set the folder sync info properly
249      * without hitting the server again. It also applies to conflicts that involves unmanaged
250      * local resources.
251      *
252      * @return an IStatus with the following severity and codes
253      * <ul>
254      * <li>IStatus.WARNING
255      * <ul>
256      * <li>INVALID_RESOURCE_TYPE - makeInSync only works on folders
257      * <li>INVALID_SYNC_KIND - sync direction must be incoming or conflicting
258      * </ul>
259      * <li>IStatus.ERROR
260      * <ul>
261      * <li>PARENT_NOT_MANAGED - the local parent of the resource is not under CVS control
262      * <li>SYNC_INFO_CONFLICTS - Sync info already exists locally and differs from the info
263      * in the remote handle.
264      * <li>REMOTE_DOES_NOT_EXIST - There is no local sync info and there is no remote handle
265      * </ul>
266      * </ul>
267      */

268      public IStatus makeInSync() throws CVSException {
269         
270         // Only works on folders
271
if (getLocal().getType() == IResource.FILE) {
272             return new CVSStatus(IStatus.WARNING, INVALID_RESOURCE_TYPE, NLS.bind(CVSMessages.CVSSyncInfo_7, new String JavaDoc[] { getLocal().getFullPath().toString()}), getLocal());
273         }
274         
275         // Only works on outgoing and conflicting changes
276
boolean outgoing = (getKind() & DIRECTION_MASK) == OUTGOING;
277         if (outgoing) {
278             return new CVSStatus(IStatus.WARNING, INVALID_SYNC_KIND, NLS.bind(CVSMessages.CVSSyncInfo_8, new String JavaDoc[] { getLocal().getFullPath().toString() }), getLocal());
279         }
280         
281         // The parent must be managed
282
ICVSFolder local = CVSWorkspaceRoot.getCVSFolderFor((IContainer)getLocal());
283         if (getLocal().getType() == IResource.FOLDER && ! local.getParent().isCVSFolder())
284             return new CVSStatus(IStatus.ERROR, PARENT_NOT_MANAGED, NLS.bind(CVSMessages.CVSSyncInfo_9, new String JavaDoc[] { getLocal().getFullPath().toString() }), getLocal());
285         
286         // Ensure that the folder exists locally
287
if (! local.exists()) {
288             local.mkdir();
289         }
290         
291         // If the folder already has CVS info, check that the remote and local match
292
RemoteFolder remote = (RemoteFolder)getRemote();
293         if((local.isManaged() || getLocal().getType() == IResource.PROJECT) && local.isCVSFolder()) {
294             // If there's no remote, assume everything is OK
295
if (remote == null) return Status.OK_STATUS;
296             // Verify that the root and repository are the same
297
FolderSyncInfo remoteInfo = remote.getFolderSyncInfo();
298             FolderSyncInfo localInfo = local.getFolderSyncInfo();
299             if ( ! localInfo.getRoot().equals(remoteInfo.getRoot())) {
300                 return new CVSStatus(IStatus.ERROR, SYNC_INFO_CONFLICTS, NLS.bind(CVSMessages.CVSRemoteSyncElement_rootDiffers, (new Object JavaDoc[] {local.getName(), remoteInfo.getRoot(), localInfo.getRoot()})),getLocal());
301             } else if ( ! localInfo.getRepository().equals(remoteInfo.getRepository())) {
302                 return new CVSStatus(IStatus.ERROR, SYNC_INFO_CONFLICTS, NLS.bind(CVSMessages.CVSRemoteSyncElement_repositoryDiffers, (new Object JavaDoc[] {local.getName(), remoteInfo.getRepository(), localInfo.getRepository()})),getLocal());
303             }
304             // The folders are in sync so just return
305
return Status.OK_STATUS;
306         }
307         
308         // The remote must exist if the local is not managed
309
if (remote == null) {
310             return new CVSStatus(IStatus.ERROR, REMOTE_DOES_NOT_EXIST, NLS.bind(CVSMessages.CVSSyncInfo_10, new String JavaDoc[] { getLocal().getFullPath().toString() }),getLocal());
311         }
312         
313         // Since the parent is managed, this will also set the resource sync info. It is
314
// impossible for an incoming folder addition to map to another location in the
315
// repo, so we assume that using the parent's folder sync as a basis is safe.
316
// It is also impossible for an incomming folder to be static.
317
FolderSyncInfo remoteInfo = remote.getFolderSyncInfo();
318         FolderSyncInfo localInfo = local.getParent().getFolderSyncInfo();
319         MutableFolderSyncInfo newInfo = remoteInfo.cloneMutable();
320         newInfo.setTag(localInfo.getTag());
321         newInfo.setStatic(false);
322         local.setFolderSyncInfo(newInfo);
323         return Status.OK_STATUS;
324     }
325     
326     public String JavaDoc toString() {
327         IResourceVariant base = getBase();
328         IResourceVariant remote = getRemote();
329         StringBuffer JavaDoc result = new StringBuffer JavaDoc(super.toString());
330         result.append("Local: "); //$NON-NLS-1$
331
result.append(getLocal().toString());
332         result.append(" Base: "); //$NON-NLS-1$
333
if (base == null) {
334             result.append("none"); //$NON-NLS-1$
335
} else {
336             result.append(base.toString());
337         }
338         result.append(" Remote: "); //$NON-NLS-1$
339
if (remote == null) {
340             result.append("none"); //$NON-NLS-1$
341
} else {
342             result.append(remote.toString());
343         }
344         return result.toString();
345     }
346     
347     /* (non-Javadoc)
348      * @see org.eclipse.team.core.subscribers.SyncInfo#getContentIdentifier()
349      */

350     public String JavaDoc getLocalContentIdentifier() {
351         try {
352             IResource local = getLocal();
353             if (local != null && local.getType() == IResource.FILE) {
354                 // it's a file, return the revision number if we can find one
355
ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor((IFile) local);
356                 ResourceSyncInfo info = cvsFile.getSyncInfo();
357                 if (info != null) {
358                     return info.getRevision();
359                 }
360             }
361         } catch (CVSException e) {
362             CVSProviderPlugin.log(e);
363             return null;
364         }
365         return null;
366     }
367 }
368
Popular Tags