*** empty log message ***
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java index d081a16..df51bc1 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java
@@ -316,6 +316,10 @@ workspace.removeResourceChangeListener(fileModificationManager); workspace.removeResourceChangeListener(addDeleteMoveListener); + // remove all of this plugin's save participants. This is easier than having + // each class that added itself as a participant to have to listen to shutdown. + workspace.removeSaveParticipant(this); + deleteCacheDirectory(); }
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java index 63bb0f0..74fcea3 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java
@@ -499,7 +499,8 @@ EclipseSynchronizer.getInstance().flushDirtyCache(getIResource(), IResource.DEPTH_ZERO); return; } - setModified(isModified(getSyncInfo())); + //setModified(isModified(getSyncInfo())); + flushWithAncestors(); } /** @@ -514,7 +515,18 @@ } public boolean handleModification(boolean forAddition) throws CVSException { - if (isIgnored()) return false; + if (isIgnored()) { + // Special case handling for when a resource passes from the un-managed state + // to the ignored state (e.g. ignoring the ignore file). Parent dirty state must be + // recalculated but since the resource's end state is ignored there is a lot of code + // in the plugin that simply disregards the change to the resource. + // There may be a better was of handling resources that transition from un-managed to + // ignored but for now this seems like the safest change. + if(! resource.isDerived()) { + flushWithAncestors(); + } + return false; + } if (EclipseSynchronizer.getInstance().contentsChangedByUpdate(getIFile())) return false; if (forAddition) { @@ -528,10 +540,8 @@ } /** - * Method setModified sets the modified status of the reciever. This method + * Sets the modified status of the receiver. This method * returns true if there was a change in the modified status of the file. - * @param iFile - * @param b */ private boolean setModified(boolean modified) throws CVSException { try {
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java index 265c79d..fe77ff0 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java
@@ -354,7 +354,9 @@ * @param b */ protected void adjustModifiedCount(boolean modified) throws CVSException { - flushWithAncestors(); + if (isModified() != modified) { + flushWithAncestors(); + } // if (EclipseSynchronizer.getInstance().adjustModifiedCount((IContainer)getIResource(), modified)) { // ((EclipseFolder)getParent()).adjustModifiedCount(modified); // } @@ -440,6 +442,12 @@ private String determineDirtyCount(String indicator, boolean shared) throws CVSException { IContainer container = (IContainer)getIResource(); ICVSResource[] children = members(ALL_UNIGNORED_MEMBERS); + + if (Policy.DEBUG_DIRTY_CACHING) { + System.out.println("checking isModified() recursively for " //$NON-NLS-1$ + +getPath()); + } + int count = 0; Set deletedChildren = new HashSet(); for (int i = 0; i < children.length; i++) {
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java index a3300cc..60ad3d4 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
@@ -1280,6 +1280,12 @@ */ protected boolean setModified(IResource container, boolean modified) throws CVSException { String indicator = modified ? IS_DIRTY_INDICATOR : NOT_DIRTY_INDICATOR; + + // DECORATOR this state change check is error prone. it is quite possible that + // another thread updated the dirty state (e.g. the decorator) and thus the returned + // value from this method will be wrong and lead the caller to make assumptions + // that can be wrong. That the state has not changed, but it has just too quickly. + // if it's already set, no need to set the property or adjust the parents count if (indicator.equals(getDirtyIndicator(container))) return false; // set the dirty indicator and adjust the parent accordingly @@ -1406,7 +1412,10 @@ } getSyncInfoCacheFor(resource).flushDirtyCache(resource); } finally { - flushDirtyCacheWithAncestors(resource.getParent()); + IContainer parent = resource.getParent(); + if(! alreadyflushed(parent)) { + flushDirtyCacheWithAncestors(parent); + } } } finally { endOperation(null); @@ -1414,6 +1423,14 @@ } /** + * @param parent + * @return boolean + */ + private boolean alreadyflushed(IContainer resource) throws CVSException { + return getSyncInfoCacheFor(resource).isDirtyCacheFlushed(resource); + } + + /** * Method updated flags the objetc as having been modfied by the updated * handler. This flag is read during the resource delta to determine whether * the modification made the file dirty or not.
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java index bd20e5e..8f9da85 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FileModificationManager.java
@@ -59,6 +59,9 @@ if (!project.isAccessible()) { return false; } + if ((delta.getFlags() & IResourceDelta.OPEN) != 0) { + return false; + } if (RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId()) == null) { return false; } @@ -168,9 +171,8 @@ private void resourceAdded(IResource resource) throws CoreException { try { EclipseResource cvsResource = (EclipseResource)CVSWorkspaceRoot.getCVSResourceFor(resource); - if (cvsResource.handleModification(true /* addition */)) { + cvsResource.handleModification(true /* addition */); modifiedResources.add(resource); - } } catch (CVSException e) { throw e.toCoreException(); }
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java index fd81e87..c48c508 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
@@ -107,6 +107,7 @@ newInfo.setKeywordMode(Command.KSUBST_TEXT_EXPAND); newInfo.setTag(tag); syncBytes = newInfo.getBytes(); + setWorkspaceSyncState(workspaceSyncState); } public RemoteFile(RemoteFolder parent, byte[] syncBytes) throws CVSException {
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SessionPropertySyncInfoCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SessionPropertySyncInfoCache.java index fb4f969..a4e132c 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SessionPropertySyncInfoCache.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SessionPropertySyncInfoCache.java
@@ -15,10 +15,17 @@ import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceVisitor; +import org.eclipse.core.resources.ISaveContext; +import org.eclipse.core.resources.ISaveParticipant; +import org.eclipse.core.resources.ISynchronizer; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.QualifiedName; +import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; import org.eclipse.team.internal.ccvs.core.Policy; @@ -27,17 +34,31 @@ /** * This cache uses session properties to hold the bytes representing the sync - * info + * info. In addition when the workbench closes or a project is closed, the dirty + * state for all cvs managed folders are persisted using the resource's plugin + * synchronizer. */ -/*package*/ class SessionPropertySyncInfoCache extends SyncInfoCache { +/*package*/ class SessionPropertySyncInfoCache extends SyncInfoCache implements ISaveParticipant { // key used on a folder to indicate that the resource sync has been cahced for it's children private static final QualifiedName RESOURCE_SYNC_CACHED_KEY = new QualifiedName(CVSProviderPlugin.ID, "resource-sync-cached"); //$NON-NLS-1$ + private static final QualifiedName FOLDER_SYNC_RESTORED_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-sync-restored"); //$NON-NLS-1$ + private static final Object RESOURCE_SYNC_CACHED = new Object(); + private static final Object FOLDER_SYNC_RESTORED = new Object(); /*package*/ static final String[] NULL_IGNORES = new String[0]; private static final FolderSyncInfo NULL_FOLDER_SYNC_INFO = new FolderSyncInfo("", "", null, false); //$NON-NLS-1$ //$NON-NLS-2$ + /*package*/ SessionPropertySyncInfoCache() { + try { + // this save participant is removed when the plugin is shutdown. + ResourcesPlugin.getWorkspace().addSaveParticipant(CVSProviderPlugin.getPlugin(), this); + } catch (CoreException e) { + CVSProviderPlugin.log(e.getStatus()); + } + } + /** * If not already cached, loads and caches the folder ignores sync for the container. * Folder must exist and must not be the workspace root. @@ -206,14 +227,28 @@ } private void internalSetDirtyIndicator(IContainer container, String indicator) throws CVSException { try { - container.setPersistentProperty(IS_DIRTY, indicator); + container.setSessionProperty(IS_DIRTY, indicator); } catch (CoreException e) { throw CVSException.wrapException(e); } } private String internalGetDirtyIndicator(IContainer container) throws CVSException { try { - return container.getPersistentProperty(IS_DIRTY); + String di = (String)container.getSessionProperty(IS_DIRTY); + + // if the session property is not available then restore from persisted sync info. At this + // time the sync info is not flushed because we don't want the workspace to generate + // a delta. Since the sync info is not flushed another session property is used to remember + // that the sync info was already converted to a session property and has become stale. + if(di == null && container.getSessionProperty(FOLDER_SYNC_RESTORED_KEY) == null) { + byte [] diBytes = ResourcesPlugin.getWorkspace().getSynchronizer().getSyncInfo(RESOURCE_SYNC_KEY, container); + if(diBytes != null) { + di = new String(diBytes); + setDirtyIndicator(container, di); + } + container.setSessionProperty(FOLDER_SYNC_RESTORED_KEY, FOLDER_SYNC_RESTORED); + } + return di; } catch (CoreException e) { throw CVSException.wrapException(e); } @@ -260,7 +295,7 @@ } else { resource.setSessionProperty(DIRTY_COUNT, null); resource.setSessionProperty(DELETED_CHILDREN, null); - resource.setPersistentProperty(IS_DIRTY, null); + resource.setSessionProperty(IS_DIRTY, null); } } catch (CoreException e) { throw CVSException.wrapException(e); @@ -328,6 +363,10 @@ /*package*/ void markFileAsUpdated(IFile file) throws CVSException { try { file.setSessionProperty(CLEAN_UPDATE, UPDATED_INDICATOR); + + // update dirty state so that decorators don't have to recompute after + // an update is completed. + contentsChangedByUpdate(file); } catch (CoreException e) { throw CVSException.wrapException(e); } @@ -394,4 +433,88 @@ throw CVSException.wrapException(e); } } -} + + /* (non-Javadoc) + * @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#isDirtyCacheFlushed(org.eclipse.core.resources.IContainer) + */ + boolean isDirtyCacheFlushed(IContainer resource) throws CVSException { + if (resource.exists()) { + try { + return resource.getSessionProperty(IS_DIRTY) == null; + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.core.resources.ISaveParticipant#doneSaving(org.eclipse.core.resources.ISaveContext) + */ + public void doneSaving(ISaveContext context) { + } + + /* (non-Javadoc) + * @see org.eclipse.core.resources.ISaveParticipant#prepareToSave(org.eclipse.core.resources.ISaveContext) + */ + public void prepareToSave(ISaveContext context) throws CoreException { + } + + /* (non-Javadoc) + * @see org.eclipse.core.resources.ISaveParticipant#rollback(org.eclipse.core.resources.ISaveContext) + */ + public void rollback(ISaveContext context) { + } + + /* (non-Javadoc) + * @see org.eclipse.core.resources.ISaveParticipant#saving(org.eclipse.core.resources.ISaveContext) + */ + public void saving(ISaveContext context) throws CoreException { + boolean fullSave = (context.getKind() == ISaveContext.FULL_SAVE); + boolean projectSave = (context.getKind() == ISaveContext.PROJECT_SAVE); + + if(projectSave || fullSave) { + // persist all session properties for folders into sync info. + final ISynchronizer synchronizer = ResourcesPlugin.getWorkspace().getSynchronizer(); + synchronizer.add(RESOURCE_SYNC_KEY); + + // traverse the workspace looking for CVS managed projects or just the + // specific projects being closed + IProject[] projects; + if(projectSave) { + projects = new IProject[1]; + projects[0] = context.getProject(); + } else { + projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + } + for (int i = 0; i < projects.length; i++) { + IProject project = projects[i]; + RepositoryProvider provider = RepositoryProvider.getProvider( + project, + CVSProviderPlugin.getTypeId()); + + // found a project managed by CVS, convert each session property on a + // folder to a sync object. + if (provider != null) { + project.accept(new IResourceVisitor() { + public boolean visit(IResource resource) throws CoreException { + if(resource.getType() != IResource.FILE) { + String di = null; + try { + di = getDirtyIndicator(resource); + } catch (CVSException e) { + // continue traversal + CVSProviderPlugin.log(e); + } + if(di != null) { + synchronizer.setSyncInfo(RESOURCE_SYNC_KEY, resource, di.getBytes()); + } + } + return true; + } + }); + } + } + } + } +} \ No newline at end of file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SyncInfoCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SyncInfoCache.java index 6d49600..6da5e77 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SyncInfoCache.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SyncInfoCache.java
@@ -141,4 +141,10 @@ * @param container */ /*package*/ abstract void setResourceSyncInfoCached(IContainer container) throws CVSException; + + /** + * @param resource + * @return boolean + */ + /*package*/ abstract boolean isDirtyCacheFlushed(IContainer resource) throws CVSException; }
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SynchronizerSyncInfoCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SynchronizerSyncInfoCache.java index ba1b54c..a312785 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SynchronizerSyncInfoCache.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SynchronizerSyncInfoCache.java
@@ -449,4 +449,11 @@ boolean isFolderSyncInfoCached(IContainer container) throws CVSException { return true; } + + /* (non-Javadoc) + * @see org.eclipse.team.internal.ccvs.core.resources.SyncInfoCache#isDirtyCacheFlushed(org.eclipse.core.resources.IContainer) + */ + boolean isDirtyCacheFlushed(IContainer resource) throws CVSException { + return false; + } }
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/AddDeleteMoveListener.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/AddDeleteMoveListener.java index cf53ff9..a01d648 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/AddDeleteMoveListener.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/AddDeleteMoveListener.java
@@ -201,6 +201,13 @@ for (int i = 0; i < projectDeltas.length; i++) { final IResourceDelta delta = projectDeltas[i]; IResource resource = delta.getResource(); + + if (resource.getType() == IResource.PROJECT) { + // If the project is not accessible, don't process it + if (!resource.isAccessible()) continue; + if ((delta.getFlags() & IResourceDelta.OPEN) != 0) continue; + } + RepositoryProvider provider = RepositoryProvider.getProvider(resource.getProject(), CVSProviderPlugin.getTypeId()); // Make sure that the project is a CVS folder.
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileChangeListener.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileChangeListener.java index 5f6f546..1eda04c 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileChangeListener.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileChangeListener.java
@@ -73,6 +73,7 @@ if (resource.getType() == IResource.PROJECT) { // If the project is not accessible, don't process it if (!resource.isAccessible()) return false; + if ((delta.getFlags() & IResourceDelta.OPEN) != 0) return false; } String name = resource.getName();
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SharingWizard.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SharingWizard.java index fd1e876..660284a 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SharingWizard.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SharingWizard.java
@@ -431,9 +431,8 @@ // for now, just unmanage folder.unmanage(null); } - folder.acceptChildren(this); } - }); + }, true /* recurse */); } catch (CVSException e) { // log the exception and return null CVSUIPlugin.log(e);