Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Valenta2003-09-26 20:59:40 +0000
committerMichael Valenta2003-09-26 20:59:40 +0000
commit9d496d5dfc29f48537f3d06094010aca0a7c5ea4 (patch)
treebc27ad60a245d756639acc30b5fb477bd0da3337
parente817e2268c0de520fe0b064fd143fccd90468954 (diff)
downloadeclipse.platform.team-9d496d5dfc29f48537f3d06094010aca0a7c5ea4.tar.gz
eclipse.platform.team-9d496d5dfc29f48537f3d06094010aca0a7c5ea4.tar.xz
eclipse.platform.team-9d496d5dfc29f48537f3d06094010aca0a7c5ea4.zip
43695: ResourceException: The resource tree is locked
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java15
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSWorkspaceSubscriber.java29
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/IResourceStateChangeListener.java11
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java101
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/SessionPropertySyncInfoCache.java16
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/DeferredResourceChangeHandler.java2
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ReentrantLock.java37
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileChangeListener.java73
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java11
-rw-r--r--tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java26
-rw-r--r--tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/BatchedTestSetup.java2
-rw-r--r--tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/EclipseSynchronizerTest.java1
-rw-r--r--tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/IsModifiedTests.java8
13 files changed, 229 insertions, 103 deletions
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 def41934c..0fb4c5c68 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
@@ -479,6 +479,21 @@ public class CVSProviderPlugin extends Plugin {
}
}
+ public static void broadcastExternalSyncInfoChanges(final IResource[] resources) {
+ for(Iterator it=listeners.iterator(); it.hasNext();) {
+ final IResourceStateChangeListener listener = (IResourceStateChangeListener)it.next();
+ ISafeRunnable code = new ISafeRunnable() {
+ public void run() throws Exception {
+ listener.externalSyncInfoChange(resources);
+ }
+ public void handleException(Throwable e) {
+ // don't log the exception....it is already being logged in Platform#run
+ }
+ };
+ Platform.run(code);
+ }
+ }
+
public static void broadcastDecoratorEnablementChanged(final boolean enabled) {
for(Iterator it=decoratorEnablementListeners.iterator(); it.hasNext();) {
final ICVSDecoratorEnablementListener listener = (ICVSDecoratorEnablementListener)it.next();
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSWorkspaceSubscriber.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSWorkspaceSubscriber.java
index 615e2e067..51767a0d7 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSWorkspaceSubscriber.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSWorkspaceSubscriber.java
@@ -19,6 +19,7 @@ import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.team.core.RepositoryProvider;
@@ -104,6 +105,32 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe
}
/* (non-Javadoc)
+ * @see org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener#externalSyncInfoChange(org.eclipse.core.resources.IResource[])
+ */
+ public void externalSyncInfoChange(IResource[] changedResources) {
+ for (int i = 0; i < changedResources.length; i++) {
+ IResource resource = changedResources[i];
+ try {
+ // User may need to Refresh with Remote if there is remote bytes for a
+ // changed file
+ if (resource.getType() == IResource.FILE
+ && (resource.exists() || resource.isPhantom())) {
+ if (remoteSynchronizer.getSyncBytes(resource) != null) {
+ // TODO: it would be nice to be able to start a refresh job
+ // but this needs refactoring
+ // The following is a temporary measure (see bug 43774)
+ CVSProviderPlugin.log(new CVSStatus(IStatus.WARNING, "The incoming changes of CVS Workspace subscriber in the Synchronize view may be stale. Perform a Refresh with Remote on resource " + resource.getFullPath().toString()));
+ }
+ }
+ } catch (TeamException e) {
+ CVSProviderPlugin.log(e);
+ }
+ }
+
+ fireTeamResourceChange(TeamDelta.asSyncChangedDeltas(this, changedResources));
+ }
+
+ /* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener#resourceModified(org.eclipse.core.resources.IResource[])
*/
public void resourceModified(IResource[] changedResources) {
@@ -163,8 +190,8 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe
// We need to do a scheduling rule on the project to
// avoid overly desctructive operations from occuring
// while we gather sync info
- Platform.getJobManager().beginRule(resource);
infinite.beginTask(null, 512);
+ Platform.getJobManager().beginRule(resource, Policy.subMonitorFor(infinite, 1));
resource.accept(new IResourceVisitor() {
public boolean visit(IResource innerResource) throws CoreException {
try {
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/IResourceStateChangeListener.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/IResourceStateChangeListener.java
index 619c9b0fc..b47e3a7f5 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/IResourceStateChangeListener.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/IResourceStateChangeListener.java
@@ -45,6 +45,17 @@ public interface IResourceStateChangeListener extends EventListener{
public void resourceSyncInfoChanged(IResource[] changedResources);
/**
+ * Notifies this listener that the resource sync info may have been changed
+ * by an external tool. It is not always easy to differentiate external
+ * changes from intenal ones. Therefore, the changed resources may include
+ * some whose sync info was changed internally. This method is called
+ * from a POST_CHANGE delta listener so the workspace cannot be modified.
+ *
+ * @param changeResources that have sync info state changes
+ */
+ public void externalSyncInfoChange(IResource[] changedResources);
+
+ /**
* Notifies this listener that the resource's have been modified. This
* doesn't necessarily mean that the resource state isModified. The listener
* must check the state.
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 a9465ad4c..7d370b59d 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
@@ -137,7 +137,7 @@ public class EclipseSynchronizer implements IFlushOperation {
Policy.bind("EclipseSynchronizer.ErrorSettingFolderSync", folder.getFullPath().toString())); //$NON-NLS-1$
}
try {
- beginBatching(folder);
+ beginBatching(folder, null);
try {
beginOperation();
// get the old info
@@ -185,7 +185,7 @@ public class EclipseSynchronizer implements IFlushOperation {
public void deleteFolderSync(IContainer folder) throws CVSException {
if (folder.getType() == IResource.ROOT || !isValid(folder)) return;
try {
- beginBatching(folder);
+ beginBatching(folder, null);
try {
beginOperation();
// iterate over all children with sync info and prepare notifications
@@ -235,7 +235,7 @@ public class EclipseSynchronizer implements IFlushOperation {
Policy.bind("EclipseSynchronizer.ErrorSettingResourceSync", resource.getFullPath().toString())); //$NON-NLS-1$
}
try {
- beginBatching(resource);
+ beginBatching(resource, null);
try {
beginOperation();
// cache resource sync for siblings, set for self, then notify
@@ -312,7 +312,7 @@ public class EclipseSynchronizer implements IFlushOperation {
Policy.bind("EclipseSynchronizer.ErrorSettingResourceSync", resource.getFullPath().toString())); //$NON-NLS-1$
}
try {
- beginBatching(resource);
+ beginBatching(resource, null);
try {
beginOperation();
// cache resource sync for siblings, set for self, then notify
@@ -337,7 +337,7 @@ public class EclipseSynchronizer implements IFlushOperation {
IContainer parent = resource.getParent();
if (parent == null || parent.getType() == IResource.ROOT || !isValid(parent)) return;
try {
- beginBatching(resource);
+ beginBatching(resource, null);
try {
beginOperation();
// cache resource sync for siblings, delete for self, then notify
@@ -397,7 +397,7 @@ public class EclipseSynchronizer implements IFlushOperation {
Policy.bind("EclipseSynchronizer.ErrorSettingIgnorePattern", folder.getFullPath().toString())); //$NON-NLS-1$
}
try {
- beginBatching(folder);
+ beginBatching(folder, null);
try {
beginOperation();
String[] ignores = SyncFileWriter.readCVSIgnoreEntries(folder);
@@ -474,8 +474,8 @@ public class EclipseSynchronizer implements IFlushOperation {
*
* @param monitor the progress monitor, may be null
*/
- public void beginBatching(IResource resource) {
- resourceLock.acquire(resource, this /* IFlushOperation */);
+ public void beginBatching(IResource resource, IProgressMonitor monitor) {
+ resourceLock.acquire(resource, this /* IFlushOperation */, monitor);
}
/**
@@ -553,12 +553,12 @@ public class EclipseSynchronizer implements IFlushOperation {
monitor = Policy.monitorFor(monitor);
monitor.beginTask(null, 10);
try {
- beginBatching(root);
+ beginBatching(root, Policy.subMonitorFor(monitor, 1));
try {
beginOperation();
try {
// Flush changes to disk
- resourceLock.flush(Policy.subMonitorFor(monitor, 7));
+ resourceLock.flush(Policy.subMonitorFor(monitor, 8));
} finally {
// Purge the in-memory cache
sessionPropertyCache.purgeCache(root, deep);
@@ -567,7 +567,7 @@ public class EclipseSynchronizer implements IFlushOperation {
endOperation();
}
} finally {
- endBatching(root, Policy.subMonitorFor(monitor, 3));
+ endBatching(root, Policy.subMonitorFor(monitor, 1));
monitor.done();
}
}
@@ -576,15 +576,15 @@ public class EclipseSynchronizer implements IFlushOperation {
monitor = Policy.monitorFor(monitor);
monitor.beginTask(null, 100);
try {
- beginBatching(project);
+ beginBatching(project, Policy.subMonitorFor(monitor, 10));
// Flush
- flush(project, true /* deep */, monitor);
+ flush(project, true /* deep */, Policy.subMonitorFor(monitor, 80));
// forget about pruned folders however the top level pruned folder will have resource sync (e.g.
// a line in the Entry file). As a result the folder is managed but is not a CVS folder.
synchronizerCache.purgeCache(project, true);
} finally {
- endBatching(project, Policy.subMonitorFor(monitor, 20));
+ endBatching(project, Policy.subMonitorFor(monitor, 10));
monitor.done();
}
}
@@ -602,20 +602,47 @@ public class EclipseSynchronizer implements IFlushOperation {
* children and appropriate state change events are broadcasts to state change
* listeners.
*/
- public void syncFilesChanged(IContainer[] roots) throws CVSException {
- try {
- for (int i = 0; i < roots.length; i++) {
- IContainer root = roots[i];
- sessionPropertyCache.purgeCache(root, false /*don't flush children*/);
- List changedPeers = new ArrayList();
- changedPeers.add(root);
- changedPeers.addAll(Arrays.asList(root.members()));
- IResource[] resources = (IResource[]) changedPeers.toArray(new IResource[changedPeers.size()]);
- CVSProviderPlugin.broadcastSyncInfoChanges(resources);
+ public void ignoreFilesChanged(IContainer[] roots) throws CVSException {
+ for (int i = 0; i < roots.length; i++) {
+ IContainer container = roots[i];
+ try {
+ Set changed = new HashSet();
+ beginBatching(container, null);
+ try {
+ beginOperation();
+ changed.addAll(Arrays.asList(
+ sessionPropertyCache.purgeCache(container, false /*don't flush children*/)));
+ } finally {
+ endOperation();
+ }
+ if (!changed.isEmpty()) {
+ CVSProviderPlugin.broadcastSyncInfoChanges(
+ (IResource[]) changed.toArray(new IResource[changed.size()]));
+ }
+ } finally {
+ endBatching(container, null);
+ }
+ }
+ }
+
+ public void syncFilesChangedExternally(IContainer[] changedMetaFiles, IFile[] externalDeletions) throws CVSException {
+ List changed = new ArrayList();
+ for (int i = 0; i < changedMetaFiles.length; i++) {
+ IContainer container = changedMetaFiles[i];
+ if (!isWithinActiveOperationScope(container)) {
+ changed.addAll(Arrays.asList(
+ sessionPropertyCache.purgeCache(container, false /*don't flush children*/)));
+ }
+ }
+ for (int i = 0; i < externalDeletions.length; i++) {
+ IFile file = externalDeletions[i];
+ if (!isWithinActiveOperationScope(file)) {
+ sessionPropertyCache.purgeCache(file.getParent(), false /*don't flush children*/);
+ changed.add(file);
}
- } catch (CoreException e) {
- throw CVSException.wrapException(e);
}
+ CVSProviderPlugin.broadcastExternalSyncInfoChanges(
+ (IResource[]) changed.toArray(new IResource[changed.size()]));
}
/**
@@ -625,7 +652,7 @@ public class EclipseSynchronizer implements IFlushOperation {
public void prepareForDeletion(IResource resource) throws CVSException {
if (!resource.exists()) return;
try {
- beginBatching(resource);
+ beginBatching(resource, null);
try {
beginOperation();
// Flush the dirty info for the resource and it's ancestors.
@@ -1185,15 +1212,15 @@ public class EclipseSynchronizer implements IFlushOperation {
monitor = Policy.monitorFor(monitor);
monitor.beginTask(null, 100);
try {
- beginBatching(file);
+ beginBatching(file, Policy.subMonitorFor(monitor, 10));
ResourceSyncInfo info = getResourceSync(file);
// The file must exist remotely and locally
if (info == null || info.isAdded() || info.isDeleted())
return;
- SyncFileWriter.writeFileToBaseDirectory(file, monitor);
+ SyncFileWriter.writeFileToBaseDirectory(file, Policy.subMonitorFor(monitor, 80));
resourceChanged(file);
} finally {
- endBatching(file, Policy.subMonitorFor(monitor, 20));
+ endBatching(file, Policy.subMonitorFor(monitor, 10));
monitor.done();
}
}
@@ -1202,15 +1229,15 @@ public class EclipseSynchronizer implements IFlushOperation {
monitor = Policy.monitorFor(monitor);
monitor.beginTask(null, 100);
try {
- beginBatching(file);
+ beginBatching(file, Policy.subMonitorFor(monitor, 10));
ResourceSyncInfo info = getResourceSync(file);
// The file must exist remotely
if (info == null || info.isAdded())
return;
- SyncFileWriter.restoreFileFromBaseDirectory(file, monitor);
+ SyncFileWriter.restoreFileFromBaseDirectory(file, Policy.subMonitorFor(monitor, 80));
resourceChanged(file);
} finally {
- endBatching(file, Policy.subMonitorFor(monitor, 20));
+ endBatching(file, Policy.subMonitorFor(monitor, 10));
monitor.done();
}
}
@@ -1257,7 +1284,7 @@ public class EclipseSynchronizer implements IFlushOperation {
for (int i = 0; i < folders.length; i++) {
IContainer parent = folders[i];
try {
- beginBatching(parent);
+ beginBatching(parent, null);
try {
beginOperation();
cacheResourceSyncForChildren(parent, false);
@@ -1313,10 +1340,10 @@ public class EclipseSynchronizer implements IFlushOperation {
monitor = Policy.monitorFor(monitor);
monitor.beginTask(null, 100);
try {
- beginBatching(rootResource);
+ beginBatching(rootResource, Policy.subMonitorFor(monitor, 10));
job.run(Policy.subMonitorFor(monitor, 80));
} finally {
- endBatching(rootResource, Policy.subMonitorFor(monitor, 20));
+ endBatching(rootResource, Policy.subMonitorFor(monitor, 10));
monitor.done();
}
}
@@ -1472,7 +1499,7 @@ public class EclipseSynchronizer implements IFlushOperation {
public void setTimeStamp(IFile file, long time) throws CVSException {
try {
- beginBatching(file);
+ beginBatching(file, null);
try {
beginOperation();
try {
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 fb3c9d50c..4348156c3 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
@@ -10,6 +10,10 @@
*******************************************************************************/
package org.eclipse.team.internal.ccvs.core.resources;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
@@ -141,23 +145,29 @@ import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter;
/**
* Purges the cache recursively for all resources beneath the container.
* There must not be any pending uncommitted changes.
+ * @return the resources whose sync info was flushed
*/
- /*package*/ void purgeCache(IContainer container, boolean deep) throws CVSException {
- if (! container.exists()) return;
+ /*package*/ IResource[] purgeCache(IContainer container, boolean deep) throws CVSException {
+ if (! container.exists()) return new IResource[0];
try {
+ Set flushed = new HashSet();
if (container.getType() != IResource.ROOT) {
safeSetSessionProperty(container, IGNORE_SYNC_KEY, null);
safeSetSessionProperty(container, FOLDER_SYNC_KEY, null);
safeSetSessionProperty(container, RESOURCE_SYNC_CACHED_KEY, null);
+ flushed.add(container);
}
IResource[] members = container.members();
for (int i = 0; i < members.length; i++) {
IResource resource = members[i];
purgeResourceSyncCache(resource);
+ flushed.add(resource);
if (deep && resource.getType() != IResource.FILE) {
- purgeCache((IContainer) resource, deep);
+ IResource[] flushedChildren = purgeCache((IContainer) resource, deep);
+ flushed.addAll(Arrays.asList(flushedChildren));
}
}
+ return (IResource[]) flushed.toArray(new IResource[flushed.size()]);
} catch (CoreException e) {
throw CVSException.wrapException(e);
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/DeferredResourceChangeHandler.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/DeferredResourceChangeHandler.java
index a57bdad8b..96b24060c 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/DeferredResourceChangeHandler.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/DeferredResourceChangeHandler.java
@@ -61,7 +61,7 @@ public class DeferredResourceChangeHandler extends BackgroundEventHandler {
if (!hasUnprocessedEvents()
|| changedIgnoreFiles.size() > NOTIFICATION_BATCHING_NUMBER) {
- EclipseSynchronizer.getInstance().syncFilesChanged(getParents(changedIgnoreFiles));
+ EclipseSynchronizer.getInstance().ignoreFilesChanged(getParents(changedIgnoreFiles));
changedIgnoreFiles.clear();
}
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ReentrantLock.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ReentrantLock.java
index 9e33acfd0..1f3adb630 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ReentrantLock.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ReentrantLock.java
@@ -70,11 +70,11 @@ public class ReentrantLock {
* acquire the rule if it is not the workspace root.
* @param resource
*/
- public void pushRule(IResource resource) {
+ public void pushRule(IResource resource, IProgressMonitor monitor) {
// The scheduling rule is either the project or the resource's parent
ISchedulingRule rule = getRuleForResoure(resource);
if (rule != NULL_SCHEDULING_RULE) {
- Platform.getJobManager().beginRule(rule);
+ Platform.getJobManager().beginRule(rule, monitor);
}
addRule(rule);
}
@@ -88,14 +88,14 @@ public class ReentrantLock {
* @throws CVSException
*/
public void popRule(IResource resource, IProgressMonitor monitor) throws CVSException {
- ISchedulingRule rule = removeRule();
- ISchedulingRule compareRule = getRuleForResoure(resource);
- Assert.isTrue(rule.equals(compareRule), "end for resource '" + resource + "' does not match stacked rule '" + rule + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
try {
if (isFlushRequired()) {
flush(monitor);
}
} finally {
+ ISchedulingRule rule = removeRule();
+ ISchedulingRule compareRule = getRuleForResoure(resource);
+ Assert.isTrue(rule.equals(compareRule), "end for resource '" + resource + "' does not match stacked rule '" + rule + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (rule != NULL_SCHEDULING_RULE) {
Platform.getJobManager().endRule(rule);
}
@@ -153,16 +153,19 @@ public class ReentrantLock {
changedFolders.clear();
}
private boolean isFlushRequired() {
- return !isNested() || !isNoneNullRules();
+ return rules.size() == 1 || remainingRulesAreNull();
}
- private boolean isNoneNullRules() {
- for (Iterator iter = rules.iterator(); iter.hasNext();) {
- ISchedulingRule rule = (ISchedulingRule) iter.next();
+ /*
+ * Return true if all but the last rule in the stack is null
+ */
+ private boolean remainingRulesAreNull() {
+ for (int i = 0; i < rules.size() - 1; i++) {
+ ISchedulingRule rule = (ISchedulingRule) rules.get(i);
if (rule != NULL_SCHEDULING_RULE) {
- return true;
+ return false;
}
}
- return false;
+ return true;
}
private void handleAbortedFlush(Throwable t) {
CVSProviderPlugin.log(new CVSStatus(IStatus.ERROR, Policy.bind("ReentrantLock.9"), t)); //$NON-NLS-1$
@@ -192,8 +195,10 @@ public class ReentrantLock {
private ThreadInfo getThreadInfo() {
Thread thisThread = Thread.currentThread();
- ThreadInfo info = (ThreadInfo)infos.get(thisThread);
- return info;
+ synchronized (infos) {
+ ThreadInfo info = (ThreadInfo)infos.get(thisThread);
+ return info;
+ }
}
private ThreadInfo getThreadInfo(IResource resource) {
@@ -208,7 +213,7 @@ public class ReentrantLock {
}
}
- public synchronized void acquire(IResource resource, IFlushOperation operation) {
+ public void acquire(IResource resource, IFlushOperation operation, IProgressMonitor monitor) {
ThreadInfo info = getThreadInfo();
synchronized (infos) {
if (info == null) {
@@ -218,7 +223,7 @@ public class ReentrantLock {
if(DEBUG) System.out.println("[" + thisThread.getName() + "] acquired CVS lock on " + resource.getFullPath()); //$NON-NLS-1$ //$NON-NLS-2$
}
}
- info.pushRule(resource);
+ info.pushRule(resource, monitor);
}
/**
@@ -227,7 +232,7 @@ public class ReentrantLock {
* On exit, the scheduling rule is held by the lock until after the runnable
* is run.
*/
- public synchronized void release(IResource resource, IProgressMonitor monitor) throws CVSException {
+ public void release(IResource resource, IProgressMonitor monitor) throws CVSException {
ThreadInfo info = getThreadInfo();
Assert.isNotNull(info, "Unmatched acquire/release."); //$NON-NLS-1$
Assert.isTrue(info.isNested(), "Unmatched acquire/release."); //$NON-NLS-1$
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 e5405078a..eff0002eb 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
@@ -64,7 +64,16 @@ public class SyncFileChangeListener implements IResourceChangeListener {
protected boolean isProjectOpening = false;
- protected DeferredResourceChangeHandler deferredHandler = new DeferredResourceChangeHandler();
+ protected static DeferredResourceChangeHandler deferredHandler = new DeferredResourceChangeHandler();
+
+ /**
+ * This accessor is for use by test cases only.
+ *
+ * @return Returns the deferredHandler.
+ */
+ public static DeferredResourceChangeHandler getDeferredHandler() {
+ return deferredHandler;
+ }
/*
* When a resource changes this method will detect if the changed resources is a meta file that has changed
@@ -77,9 +86,12 @@ public class SyncFileChangeListener implements IResourceChangeListener {
public void resourceChanged(IResourceChangeEvent event) {
try {
final Set changedContainers = new HashSet();
+ final Set externalDeletions = new HashSet();
+
setProjectOpening(false);
event.getDelta().accept(new IResourceDeltaVisitor() {
+
public boolean visit(IResourceDelta delta) throws CoreException {
IResource resource = delta.getResource();
@@ -103,8 +115,6 @@ public class SyncFileChangeListener implements IResourceChangeListener {
(delta.getFlags() & INTERESTING_CHANGES) == 0) {
return true;
}
-
- IResource[] toBeNotified = new IResource[0];
if(name.equals(SyncFileWriter.CVS_DIRNAME)) {
handleCVSDir((IContainer)resource, kind);
@@ -116,38 +126,30 @@ public class SyncFileChangeListener implements IResourceChangeListener {
if(isProjectOpening()) return true;
}
- if (EclipseSynchronizer.getInstance().isWithinActiveOperationScope(resource)) {
- // The resource change will be handled by the EclipseSynchronizer
- // Still visit the children of non-team-private members so that
- // ignore file changes will be past on to the EclipseSynchronizer
- if (isIgnoreFile(resource)) {
- deferredHandler.ignoreFileChanged((IFile)resource);
+ if(isMetaFile(resource)) {
+ IResource[] toBeNotified = handleChangedMetaFile(resource, kind);
+ if(toBeNotified.length>0 && isModifiedBy3rdParty(resource)) {
+ for (int i = 0; i < toBeNotified.length; i++) {
+ changedContainers.add(toBeNotified[i]);
+ }
+ if(Policy.DEBUG_METAFILE_CHANGES) {
+ System.out.println("[cvs] metafile changed by 3rd party: " + resource.getFullPath()); //$NON-NLS-1$
+ }
+ return false; /*don't visit any children we have all the information we need*/
}
- return (!resource.isTeamPrivateMember());
- } if(isMetaFile(resource)) {
- toBeNotified = handleChangedMetaFile(resource, kind);
} else if(isIgnoreFile(resource)) {
- toBeNotified = handleChangedIgnoreFile(resource, kind);
+ deferredHandler.ignoreFileChanged((IFile)resource);
} else if (isExternalDeletion(resource, kind)) {
- toBeNotified = handleExternalDeletion(resource);
- }
-
- if(toBeNotified.length>0 && isModifiedBy3rdParty(resource)) {
- for (int i = 0; i < toBeNotified.length; i++) {
- changedContainers.add(toBeNotified[i]);
- }
- if(Policy.DEBUG_METAFILE_CHANGES) {
- System.out.println("[cvs] metafile changed by 3rd party: " + resource.getFullPath()); //$NON-NLS-1$
- }
- return false; /*don't visit any children we have all the information we need*/
- } else {
- return true;
+ externalDeletions.add(resource);
}
+ return true;
}
}, IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS);
- if(!changedContainers.isEmpty()) {
- EclipseSynchronizer.getInstance().syncFilesChanged((IContainer[])changedContainers.toArray(new IContainer[changedContainers.size()]));
+ if(!changedContainers.isEmpty() || !externalDeletions.isEmpty()) {
+ EclipseSynchronizer.getInstance().syncFilesChangedExternally(
+ (IContainer[])changedContainers.toArray(new IContainer[changedContainers.size()]),
+ (IFile[]) externalDeletions.toArray(new IFile[externalDeletions.size()]));
}
} catch(CoreException e) {
CVSProviderPlugin.log(e);
@@ -155,19 +157,6 @@ public class SyncFileChangeListener implements IResourceChangeListener {
}
/**
- * @param resource
- * @return
- */
- protected IContainer[] handleExternalDeletion(IResource resource) {
- IContainer changedContainer = resource.getParent();
- if(changedContainer.exists()) {
- return new IContainer[] {changedContainer};
- } else {
- return new IContainer[0];
- }
- }
-
- /**
* Treat a resource as an external deletion if
* - it is a file
* - the delta says the file was removed
@@ -186,7 +175,7 @@ public class SyncFileChangeListener implements IResourceChangeListener {
if (resource.getType() != IResource.FILE) return false;
ICVSFile file = CVSWorkspaceRoot.getCVSFileFor((IFile)resource);
try {
- return (!file.isManaged() && file.getParent().isCVSFolder());
+ return (!file.isManaged() && file.getParent().isCVSFolder() && file.getParent().exists());
} catch (CVSException e) {
CVSProviderPlugin.log(e);
return false;
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java
index a63e83bb7..74508cfe1 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java
@@ -454,14 +454,21 @@ public class CVSLightweightDecorator
}
}
- /**
+ /* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener#resourceSyncInfoChanged(org.eclipse.core.resources.IResource[])
*/
public void resourceSyncInfoChanged(IResource[] changedResources) {
resourceStateChanged(changedResources);
}
- /**
+ /* (non-Javadoc)
+ * @see org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener#externalSyncInfoChange(org.eclipse.core.resources.IResource[])
+ */
+ public void externalSyncInfoChange(IResource[] changedResources) {
+ resourceStateChanged(changedResources);
+ }
+
+ /* (non-Javadoc)
* @see org.eclipse.team.internal.ccvs.core.IResourceStateChangeListener#resourceModificationStateChanged(org.eclipse.core.resources.IResource[])
*/
public void resourceModified(IResource[] changedResources) {
diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java
index 57446f958..a4ee38f3a 100644
--- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java
+++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java
@@ -32,6 +32,9 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.core.tests.harness.EclipseWorkspaceTest;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
@@ -58,6 +61,7 @@ import org.eclipse.team.internal.ccvs.core.resources.RemoteFile;
import org.eclipse.team.internal.ccvs.core.resources.RemoteFolder;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
+import org.eclipse.team.internal.ccvs.core.util.SyncFileChangeListener;
import org.eclipse.team.internal.ccvs.ui.operations.CVSOperation;
import org.eclipse.team.internal.ccvs.ui.operations.ITagOperation;
import org.eclipse.team.internal.ccvs.ui.operations.TagInRepositoryOperation;
@@ -702,5 +706,27 @@ public class EclipseTest extends EclipseWorkspaceTest {
fail("wait-problem");
}
}
+
+ public void waitForIgnoreHandlerCompletion() {
+ Job job = SyncFileChangeListener.getDeferredHandler().getEventHandlerJob();
+ final boolean[] done = new boolean[] { false };
+ job.addJobChangeListener(new JobChangeAdapter() {
+ public void done(IJobChangeEvent event) {
+ done[0] = true;
+ }
+ });
+ int count = 0;
+ while (job.getState() != Job.NONE && ! done[0]) {
+ try {
+ Thread.sleep(100);
+ count++;
+ } catch (InterruptedException e) {
+ // ignore and keep going;
+ }
+ if (count == 5) {
+ fail("Ignore handling job does not seem to be finishing");
+ }
+ }
+ }
}
diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/BatchedTestSetup.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/BatchedTestSetup.java
index fea8660b5..fc673d586 100644
--- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/BatchedTestSetup.java
+++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/BatchedTestSetup.java
@@ -24,7 +24,7 @@ public class BatchedTestSetup extends TestSetup {
}
public void setUp() throws CVSException {
- EclipseSynchronizer.getInstance().beginBatching(ResourcesPlugin.getWorkspace().getRoot());
+ EclipseSynchronizer.getInstance().beginBatching(ResourcesPlugin.getWorkspace().getRoot(), null);
}
public void tearDown() throws CVSException {
diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/EclipseSynchronizerTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/EclipseSynchronizerTest.java
index ca3338928..eecf2064a 100644
--- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/EclipseSynchronizerTest.java
+++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/EclipseSynchronizerTest.java
@@ -294,6 +294,7 @@ public class EclipseSynchronizerTest extends EclipseTest {
// ignore list
IResource cvsIgnore = project.getFile(".cvsignore");
cvsIgnore.delete(true, null);
+ waitForIgnoreHandlerCompletion();
assertIsIgnored(project.getFile("a.txt"), false);
assertIsIgnored(project.getFile("c.java"), false);
diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/IsModifiedTests.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/IsModifiedTests.java
index f1eed906a..1d9a0714c 100644
--- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/IsModifiedTests.java
+++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/IsModifiedTests.java
@@ -66,6 +66,9 @@ public class IsModifiedTests extends EclipseTest {
fail(e.getMessage());
}
}
+ public void externalSyncInfoChange(IResource[] changedResources) {
+ resourceSyncInfoChanged(changedResources);
+ }
private void recordChildren(ICVSFolder folder) {
try {
folder.accept(new ICVSResourceVisitor() {
@@ -294,6 +297,7 @@ public class IsModifiedTests extends EclipseTest {
addedResources = buildResources(project, new String[] {"ignored.txt"}, false);
assertModificationState(project, new String[] {".", "ignored.txt"}, true);
project.getFile(".cvsignore").create(new ByteArrayInputStream("ignored.txt".getBytes()), false, DEFAULT_MONITOR);
+ waitForIgnoreHandlerCompletion();
assertModificationState(project, new String[] {".", ".cvsignore"}, true);
getProvider(project).add(new IResource[] {project.getFile(".cvsignore")}, IResource.DEPTH_ZERO, DEFAULT_MONITOR);
assertModificationState(project, new String[] {".", ".cvsignore"}, true);
@@ -301,11 +305,13 @@ public class IsModifiedTests extends EclipseTest {
assertModificationState(project, null, true);
// delete the .cvsignore to see the modification come back
project.getFile(".cvsignore").delete(false, DEFAULT_MONITOR);
+ waitForIgnoreHandlerCompletion();
assertModificationState(project, new String[] {".", "ignored.txt", ".cvsignore"}, true);
commitResources(project, new String[] {".cvsignore"});
assertModificationState(project, new String[] {".", "ignored.txt"}, true);
// re-add the ignore and then delete the ignored
project.getFile(".cvsignore").create(new ByteArrayInputStream("ignored.txt".getBytes()), false, DEFAULT_MONITOR);
+ waitForIgnoreHandlerCompletion();
getProvider(project).add(new IResource[] {project.getFile(".cvsignore")}, IResource.DEPTH_ZERO, DEFAULT_MONITOR);
assertModificationState(project, new String[] {".", ".cvsignore"}, true);
commitResources(project, new String[] {".cvsignore"});
@@ -395,6 +401,7 @@ public class IsModifiedTests extends EclipseTest {
assertModificationState(project, new String[] {".", "folder1/", "folder1/ignored/", "folder1/ignored/file.txt"}, true);
// ignore the folder
project.getFile("folder1/.cvsignore").create(new ByteArrayInputStream("ignored".getBytes()), false, DEFAULT_MONITOR);
+ waitForIgnoreHandlerCompletion();
assertModificationState(project, new String[] {".", "folder1/", "folder1/.cvsignore"}, true);
getProvider(project).add(new IResource[] {project.getFile("folder1/.cvsignore")}, IResource.DEPTH_ZERO, DEFAULT_MONITOR);
assertModificationState(project, new String[] {".", "folder1/", "folder1/.cvsignore"}, true);
@@ -407,6 +414,7 @@ public class IsModifiedTests extends EclipseTest {
assertModificationState(project, new String[] {".", "folder1/", "folder1/ignored/", "folder1/ignored/file.txt"}, true);
// re-add the .cvsignore and then delete the ignored
project.getFile("folder1/.cvsignore").create(new ByteArrayInputStream("ignored".getBytes()), false, DEFAULT_MONITOR);
+ waitForIgnoreHandlerCompletion();
assertModificationState(project, new String[] {".", "folder1/", "folder1/.cvsignore"}, true);
getProvider(project).add(new IResource[] {project.getFile("folder1/.cvsignore")}, IResource.DEPTH_ZERO, DEFAULT_MONITOR);
commitResources(project, new String[] {"folder1/.cvsignore"});

Back to the top