Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Valenta2003-10-16 19:41:04 +0000
committerMichael Valenta2003-10-16 19:41:04 +0000
commit0df4a708a4c47a452f18f8860043ea6689a1b348 (patch)
treefdef089ec3ff0c8bc852a8b9d495ade47d969bff
parentbff61b7227693c8ada76d0877de33fff7a81ea03 (diff)
downloadeclipse.platform.team-0df4a708a4c47a452f18f8860043ea6689a1b348.tar.gz
eclipse.platform.team-0df4a708a4c47a452f18f8860043ea6689a1b348.tar.xz
eclipse.platform.team-0df4a708a4c47a452f18f8860043ea6689a1b348.zip
44614: [CVS] Unable to commit, NPE, broken UI
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java143
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java95
-rw-r--r--tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/cvsresources/EclipseSynchronizerTest.java228
3 files changed, 367 insertions, 99 deletions
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 36840732d..32373d967 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
@@ -596,13 +596,6 @@ public class EclipseSynchronizer implements IFlushOperation {
monitor.done();
}
}
-
- private void purgeCache(IResource resource, boolean deep) throws CVSException {
- sessionPropertyCache.purgeResourceSyncCache(resource);
- if (resource.getType() != IResource.FILE) {
- sessionPropertyCache.purgeCache((IContainer)resource, deep);
- }
- }
/**
* Called to notify the synchronizer that meta files have changed on disk, outside
@@ -654,12 +647,21 @@ public class EclipseSynchronizer implements IFlushOperation {
(IResource[]) changed.toArray(new IResource[changed.size()]));
}
- /**
- * The folder is about to be deleted (including its CVS subfolder).
- * Take any appropriate action to remember the CVS information.
+ /*
+ * The resource is about to be deleted by the move delete hook.
+ * In all cases (except when the resource doesn't exist), this method
+ * will indicate that the dirty state of the parent needs to be recomputed.
+ * For managed resources, it will move the cached sync info from the session
+ * property cache into the sycnrhonizer cache, purging the session cache.
+ * @param resource the resource about to be deleted.
+ * <p>
+ * Note taht this method is not recursive. Hence, for managed resources
+ *
+ * @returns whether children need to be prepared
+ * @throws CVSException
*/
- public void prepareForDeletion(IResource resource) throws CVSException {
- if (!resource.exists()) return;
+ /* private */ boolean prepareForDeletion(IResource resource) throws CVSException {
+ if (!resource.exists()) return false;
ISchedulingRule rule = null;
try {
rule = beginBatching(resource, null);
@@ -678,21 +680,27 @@ public class EclipseSynchronizer implements IFlushOperation {
syncBytes = convertToDeletion(syncBytes);
synchronizerCache.setCachedSyncBytes(resource, syncBytes, true);
}
+ sessionPropertyCache.purgeResourceSyncCache(resource);
resourceChanged(resource);
}
+ return false;
} else {
IContainer container = (IContainer)resource;
if (container.getType() == IResource.PROJECT) {
synchronizerCache.flush((IProject)container);
+ return false;
} else {
// Move the folder sync info into phantom space
FolderSyncInfo info = getFolderSync(container);
- if (info == null) return;
+ if (info == null) return false;
synchronizerCache.setCachedFolderSync(container, info, true);
folderChanged(container);
// move the resource sync as well
byte[] syncBytes = getSyncBytes(resource);
synchronizerCache.setCachedSyncBytes(resource, syncBytes, true);
+ sessionPropertyCache.purgeResourceSyncCache(container);
+ sessionPropertyCache.purgeCache(container, false);
+ return true;
}
}
} finally {
@@ -722,37 +730,41 @@ public class EclipseSynchronizer implements IFlushOperation {
}
/**
- * Prepare for a move or delete within the move/delete hook by moving the
- * sync info into phantom space and flushing the session properties cache.
- * This will allow sync info for deletions to be maintained in the source
- * location and sync info at the destination to be preserved as well.
+ * Prepare for the deletion of the target resource from within
+ * the move/delete hook. The method is invoked by both the
+ * deleteFile/Folder methods and for the source resource
+ * of moveFile/Folder. This method will move the cached sync info
+ * into the phantom (ISynchronizer) cache so that outgoing deletions
+ * and known remote folders are preserved.
*
* @param resource
* @param monitor
* @throws CVSException
*/
- public void prepareForMoveDelete(IResource resource, IProgressMonitor monitor) throws CVSException {
+ public void prepareForDeletion(IResource resource, IProgressMonitor monitor) throws CVSException {
// Move sync info to phantom space for the resource and all it's children
+ monitor = Policy.monitorFor(monitor);
try {
+ beginOperation();
monitor.beginTask(null, 100);
- resource.accept(new IResourceVisitor() {
- public boolean visit(IResource innerResource) throws CoreException {
- try {
- prepareForDeletion(innerResource);
- } catch (CVSException e) {
- CVSProviderPlugin.log(e);
- throw new CoreException(e.getStatus());
+ try {
+ resource.accept(new IResourceVisitor() {
+ public boolean visit(IResource innerResource) throws CoreException {
+ try {
+ return prepareForDeletion(innerResource);
+ } catch (CVSException e) {
+ CVSProviderPlugin.log(e);
+ throw new CoreException(e.getStatus());
+ }
}
- return true;
- }
- });
- } catch (CoreException e) {
- throw CVSException.wrapException(e);
+ });
+ } catch (CoreException e) {
+ throw CVSException.wrapException(e);
+ }
} finally {
+ endOperation();
monitor.done();
}
- // purge the sync info to clear the session properties
- purgeCache(resource, true);
}
/**
@@ -1542,14 +1554,69 @@ public class EclipseSynchronizer implements IFlushOperation {
}
/**
- * React to a file that was just moved by the move/delete hook.
- * @param file the file that was moved (at its new location)
+ * React to a resource that was just moved by the move/delete hook.
+ * @param resource the resource that was moved (at its new location)
*/
- public void fileMoved(IFile file) throws CVSException {
- if (!isWithinActiveOperationScope(file)) {
- sessionPropertyCache.purgeCache(file.getParent(), false /*don't flush children*/);
+ public void postMove(IResource resource) throws CVSException {
+ try {
+ beginOperation();
+ if (resource.getType() == IResource.FILE) {
+ // Purge any copied sync info so true sync info will
+ // be obtained from the synchronizer cache
+ sessionPropertyCache.purgeResourceSyncCache(resource);
+ } else {
+ IContainer container = (IContainer)resource;
+ // Purge any copied sync info
+ sessionPropertyCache.purgeCache(container, true /* deep */);
+ // Dirty all resources so old sync info will be rewritten to disk
+ try {
+ container.accept(new IResourceVisitor() {
+ public boolean visit(IResource resource) throws CoreException {
+ if (getSyncBytes(resource) != null) {
+ resourceChanged(resource);
+ }
+ if (resource.getType() != IResource.FILE) {
+ if (getFolderSync((IContainer)resource) != null) {
+ folderChanged((IContainer)resource);
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+ } catch (CoreException e) {
+ throw CVSException.wrapException(e);
+ }
+ // Flush the sync info to disk
+ flush(container, true /* deep */, null);
+ }
+ } finally {
+ endOperation();
}
-
}
+ /**
+ * This method is to be invoked only from the move/delete hook. It's purpose
+ * is to obtain the sync look in order to prevent other threads from accessing
+ * sync info while the move/delete is taking place.
+ * @param runnable
+ * @param monitor
+ * @throws CVSException
+ */
+ public void performMoveDelete(ICVSRunnable runnable, IProgressMonitor monitor) throws CVSException {
+ ISchedulingRule rule = null;
+ try {
+ monitor.beginTask(null, 100);
+ rule = beginBatching(null, null);
+ try {
+ beginOperation();
+ runnable.run(Policy.subMonitorFor(monitor, 95));
+ } finally {
+ endOperation();
+ }
+ } finally {
+ if (rule != null) endBatching(rule, Policy.subMonitorFor(monitor, 5));
+ monitor.done();
+ }
+ }
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java
index 5265ea932..8dad4e254 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java
@@ -33,7 +33,6 @@ import org.eclipse.team.internal.ccvs.core.CVSTeamProvider;
import org.eclipse.team.internal.ccvs.core.ICVSFile;
import org.eclipse.team.internal.ccvs.core.ICVSFileModificationValidator;
import org.eclipse.team.internal.ccvs.core.ICVSFolder;
-import org.eclipse.team.internal.ccvs.core.ICVSResource;
import org.eclipse.team.internal.ccvs.core.ICVSRunnable;
import org.eclipse.team.internal.ccvs.core.Policy;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
@@ -55,28 +54,39 @@ public class MoveDeleteHook implements IMoveDeleteHook {
IProgressMonitor monitor) {
try {
+ monitor.beginTask(null, 100);
+
// No special handling required for team-private members
if (file.isTeamPrivateMember()) return false;
+
// If the file is ignored by CVS then we can just delete it.
ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor(file);
if (cvsFile.isIgnored()) return false;
+
+ // If we can't check out the files, return.
+ if (!checkOutFiles(tree, new IFile[] {file}, Policy.subMonitorFor(monitor, 30))) {
+ // Return that the delete was handled because the checkout
+ // will have reported the error to the IResourceTree
+ return true;
+ }
+
// Otherwise, we need to prepare properly for the delete
- EclipseSynchronizer.getInstance().run(new ICVSRunnable() {
+ EclipseSynchronizer.getInstance().performMoveDelete(new ICVSRunnable() {
public void run(IProgressMonitor monitor) throws CVSException {
try {
- monitor.beginTask(null, 100);
- if (checkOutFiles(tree, new IFile[] {file}, Policy.subMonitorFor(monitor, 35))) {
- EclipseSynchronizer.getInstance().prepareForMoveDelete(file, Policy.subMonitorFor(monitor, 30));
- tree.standardDeleteFile(file, updateFlags, Policy.subMonitorFor(monitor, 35));
- }
+ monitor.beginTask(null, 100);
+ EclipseSynchronizer.getInstance().prepareForDeletion(file, Policy.subMonitorFor(monitor, 40));
+ tree.standardDeleteFile(file, updateFlags, Policy.subMonitorFor(monitor, 60));
} finally {
monitor.done();
}
}
- }, monitor);
+ }, Policy.subMonitorFor(monitor, 70));
} catch (CVSException e) {
tree.failed(e.getStatus());
- }
+ } finally {
+ monitor.done();
+ }
return true;
}
@@ -95,11 +105,11 @@ public class MoveDeleteHook implements IMoveDeleteHook {
try {
final ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(folder);
if (cvsFolder.isCVSFolder() && ensureCheckedOut(new IFolder[] {folder}, tree, Policy.subMonitorFor(monitor, 30))) {
- EclipseSynchronizer.getInstance().run(new ICVSRunnable() {
+ EclipseSynchronizer.getInstance().performMoveDelete(new ICVSRunnable() {
public void run(IProgressMonitor monitor) throws CVSException {
try {
monitor.beginTask(null, 100);
- EclipseSynchronizer.getInstance().prepareForMoveDelete(folder, Policy.subMonitorFor(monitor, 50));
+ EclipseSynchronizer.getInstance().prepareForDeletion(folder, Policy.subMonitorFor(monitor, 20));
tree.standardDeleteFolder(folder, updateFlags, Policy.subMonitorFor(monitor, 50));
} finally {
monitor.done();
@@ -108,7 +118,7 @@ public class MoveDeleteHook implements IMoveDeleteHook {
}, Policy.subMonitorFor(monitor, 70));
return true;
} else if (!cvsFolder.isIgnored()) {
- prepareToDelete(cvsFolder);
+ EclipseSynchronizer.getInstance().prepareForDeletion(cvsFolder.getIResource(), Policy.subMonitorFor(monitor, 70));
}
} catch (CVSException e) {
tree.failed(e.getStatus());
@@ -131,7 +141,7 @@ public class MoveDeleteHook implements IMoveDeleteHook {
// All other sync info is stored in session and persistant properties, which
// are deleted when the associated resources are deleted
try {
- EclipseSynchronizer.getInstance().prepareForDeletion(project);
+ EclipseSynchronizer.getInstance().prepareForDeletion(project, monitor);
} catch (CVSException e) {
CVSProviderPlugin.log(e);
}
@@ -150,32 +160,41 @@ public class MoveDeleteHook implements IMoveDeleteHook {
IProgressMonitor monitor) {
try {
- EclipseSynchronizer.getInstance().run(new ICVSRunnable() {
+ monitor.beginTask(null, 100);
+
+ // ensure we can write to both the source and the destination
+ IFile[] filesToCheckOut;
+ if (destination.exists()) {
+ filesToCheckOut = new IFile[] {source, destination};
+ } else {
+ filesToCheckOut = new IFile[] {source};
+ }
+ if (!checkOutFiles(tree, filesToCheckOut, Policy.subMonitorFor(monitor, 30))) {
+ // Return that the move was handled because the checkout
+ // will have reported the error to the IResourceTree
+ return true;
+ }
+
+ // Perform the move
+ EclipseSynchronizer.getInstance().performMoveDelete(new ICVSRunnable() {
public void run(IProgressMonitor monitor) throws CVSException {
try {
monitor.beginTask(null, 100);
- // ensure we can write to both the source and the destination
- IFile[] filesToCheckOut;
+ EclipseSynchronizer.getInstance().prepareForDeletion(source, Policy.subMonitorFor(monitor, 40));
if (destination.exists()) {
- filesToCheckOut = new IFile[] {source, destination};
- } else {
- filesToCheckOut = new IFile[] {source};
- }
- if (checkOutFiles(tree, filesToCheckOut, Policy.subMonitorFor(monitor, 30))) {
- EclipseSynchronizer.getInstance().prepareForMoveDelete(source, Policy.subMonitorFor(monitor, 20));
- if (destination.exists()) {
- EclipseSynchronizer.getInstance().prepareForMoveDelete(destination, Policy.subMonitorFor(monitor, 20));
- }
- tree.standardMoveFile(source, destination, updateFlags, Policy.subMonitorFor(monitor, 30));
- EclipseSynchronizer.getInstance().fileMoved(destination);
+ EclipseSynchronizer.getInstance().prepareForDeletion(destination, Policy.subMonitorFor(monitor, 20));
}
+ tree.standardMoveFile(source, destination, updateFlags, Policy.subMonitorFor(monitor, 40));
+ EclipseSynchronizer.getInstance().postMove(destination);
} finally {
monitor.done();
}
}
- }, monitor);
+ }, Policy.subMonitorFor(monitor, 70));
} catch (CVSException e) {
tree.failed(e.getStatus());
+ } finally {
+ monitor.done();
}
return true;
}
@@ -195,14 +214,15 @@ public class MoveDeleteHook implements IMoveDeleteHook {
final ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(source);
if (cvsFolder.isManaged()) {
if (!ensureCheckedOut(new IFolder[] {source, destination}, tree, Policy.subMonitorFor(monitor, 20))) return true;
- EclipseSynchronizer.getInstance().run(new ICVSRunnable() {
+ EclipseSynchronizer.getInstance().performMoveDelete(new ICVSRunnable() {
public void run(IProgressMonitor monitor) throws CVSException {
- EclipseSynchronizer.getInstance().prepareForMoveDelete(source, Policy.subMonitorFor(monitor, 20));
+ EclipseSynchronizer.getInstance().prepareForDeletion(source, Policy.subMonitorFor(monitor, 20));
if (destination.exists()) {
- EclipseSynchronizer.getInstance().prepareForMoveDelete(destination, Policy.subMonitorFor(monitor, 20));
+ EclipseSynchronizer.getInstance().prepareForDeletion(destination, Policy.subMonitorFor(monitor, 20));
}
tree.standardMoveFolder(source, destination, updateFlags, Policy.subMonitorFor(monitor, 30));
purgeCVSFolders(destination, Policy.subMonitorFor(monitor, 20));
+ EclipseSynchronizer.getInstance().postMove(destination);
}
private void purgeCVSFolders(IFolder destination, final IProgressMonitor monitor) throws CVSException {
// Delete any CVS folders
@@ -223,8 +243,7 @@ public class MoveDeleteHook implements IMoveDeleteHook {
}, Policy.subMonitorFor(monitor, 60));
return true;
} else if (!cvsFolder.isIgnored()) {
- // XXX Should be inside cvs runnable
- prepareToDelete(cvsFolder);
+ EclipseSynchronizer.getInstance().prepareForDeletion(cvsFolder.getIResource(), Policy.subMonitorFor(monitor, 60));
}
} catch (CVSException e) {
tree.failed(e.getStatus());
@@ -251,7 +270,7 @@ public class MoveDeleteHook implements IMoveDeleteHook {
// project will mean that the file deletions will be lost. It also means that phantom
// folders are lost.
try {
- EclipseSynchronizer.getInstance().prepareForDeletion(source);
+ EclipseSynchronizer.getInstance().prepareForDeletion(source, monitor);
} catch (CVSException e) {
CVSProviderPlugin.log(e);
}
@@ -318,12 +337,4 @@ public class MoveDeleteHook implements IMoveDeleteHook {
CVSTeamProvider provider = (CVSTeamProvider)RepositoryProvider.getProvider(files[0].getProject(), CVSProviderPlugin.getTypeId());
return provider;
}
-
- /*
- * Signal that the unmanaged resource is about to be deleted so that the
- * dirty count of it's parent can be reduced if appropriate.
- */
- private void prepareToDelete(ICVSResource resource) throws CVSException {
- EclipseSynchronizer.getInstance().prepareForDeletion(resource.getIResource());
- }
}
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 30dc75971..f69af7787 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
@@ -26,15 +26,18 @@ import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.CVSTag;
+import org.eclipse.team.internal.ccvs.core.ICVSRunnable;
import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.MutableResourceSyncInfo;
@@ -522,38 +525,225 @@ public class EclipseSynchronizerTest extends EclipseTest {
}
}
- /*
- * See bug 44446
+ /**
+ * Create a test project whose name is derived from the currently running test case.
+ * The resources are built using the names supplied in the given String array.
+ * Paths ending in / will be folders while others will be files. Intermediate folders
+ * are created as needed. Dummy sync info is applied to all created resources and
+ * the project is mapped to the CVS repository provider.
+ * @param resourcePaths paths of resources to be generated
+ * @return the create project
*/
- public void testRecreation() throws CoreException {
-
- // Set up a project with dummy sync info
+ protected IProject createProject(String[] resourcePaths) throws CoreException {
+ // Create the project and build the resources
IProject project = getUniqueTestProject(getName());
- sync.setFolderSync(project, dummyFolderSync(project));
-
- IFolder folder = project.getFolder("folder1");
- folder.create(false, true, null);
- sync.setFolderSync(folder, dummyFolderSync(folder));
- sync.setResourceSync(folder, dummyResourceSync(folder));
-
- IFile file = folder.getFile("file1");
- file.create(getRandomContents(), false /*force*/, null);
- sync.setResourceSync(file, dummyResourceSync(file));
+ buildResources(project, resourcePaths, true);
+
+ // Associate dummy sync info with al create resources
+ project.accept(new IResourceVisitor() {
+ public boolean visit(IResource resource) throws CoreException {
+ if (resource.getType() != IResource.PROJECT) {
+ sync.setResourceSync(resource, dummyResourceSync(resource));
+ }
+ if (resource.getType() != IResource.FILE) {
+ sync.setFolderSync((IContainer)resource, dummyFolderSync((IContainer)resource));
+ }
+ return true;
+ }
+ });
// Map the project to CVS so the Move/Delete hook works
RepositoryProvider.map(project, CVSProviderPlugin.getTypeId());
+ return project;
+ }
+
+ /**
+ * Assert that the resources at the given resource paths have sync info.
+ * Also assert that the ancestors of the resources also have sync info
+ * @param project the project containing the resources
+ * @param resourcePaths the project relative resource paths
+ * @throws CVSException
+ */
+ protected void assertHasSyncInfo(IProject project, String[] resourcePaths) throws CVSException {
+ for (int i = 0; i < resourcePaths.length; i++) {
+ String path = resourcePaths[i];
+ IResource resource = findResource(project, path);
+ assertHasSyncInfo(resource);
+ }
+ }
+
+ private IResource findResource(IProject project, String path) {
+ IResource resource = project.findMember(path);
+ if (resource == null) {
+ if (path.charAt(path.length()-1) == Path.SEPARATOR)
+ resource = (IResource) project.getFolder(path);
+ else
+ resource = (IResource) project.getFile(path);
+ }
+ return resource;
+ }
+
+ /**
+ * Assert that the resource and its ancestors have sync info
+ * @param resource the resource being queried
+ * @throws CVSException
+ */
+ protected void assertHasSyncInfo(IResource resource) throws CVSException {
+ if (resource.getType() == IResource.ROOT) return;
+ if (resource.getType() != IResource.FILE) {
+ assertNotNull("Folder should have folder sync info but does not: " + resource.getProjectRelativePath(), sync.getFolderSync((IContainer)resource));
+ }
+ if (resource.getType() != IResource.PROJECT) {
+ assertNotNull("Resource should have sync bytes but does not: " + resource.getProjectRelativePath(), sync.getSyncBytes(resource));
+ assertHasSyncInfo(resource.getParent());
+ }
+ }
+
+ /**
+ * Assert that the resources at the given resource paths do not have sync info.
+ * Also assert that the descendants of the resources also do not have sync info
+ * @param project
+ * @param resourcePaths
+ * @throws CVSException
+ */
+ private void assertHasNoSyncInfo(IProject project, String[] resourcePaths) throws CoreException {
+ for (int i = 0; i < resourcePaths.length; i++) {
+ String path = resourcePaths[i];
+ IResource resource = findResource(project, path);
+ assertHasNoSyncInfo(resource);
+ }
+ }
+
+ protected void assertHasNoSyncInfo(IResource resource) throws CoreException {
+ if (resource.getType() == IResource.ROOT) return;
+ if (resource.getType() != IResource.FILE) {
+ assertNull("Folder should not have folder sync but does: " + resource.getProjectRelativePath(), sync.getFolderSync((IContainer)resource));
+ IResource[] members = ((IContainer)resource).members();
+ for (int i = 0; i < members.length; i++) {
+ IResource child = members[i];
+ assertHasNoSyncInfo(child);
+ }
+ }
+ if (resource.getType() != IResource.PROJECT) {
+ assertNull("Resource should not have sync bytes but does: " + resource.getProjectRelativePath(), sync.getSyncBytes(resource));
+ }
+ }
+
+ public void testDeleteFile() throws CoreException {
+ // Create a project with dummy sync info
+ IProject project = createProject(new String[] {"folder1/folder2/file1", "folder1/folder2/file2"});
+
+ // Delete the file and assert old sync info is still in place and new has no sync info
+ IFile file = project.getFile("folder1/folder2/file1");
+ file.delete(false, false, null);
+ assertHasSyncInfo(project, new String[] {"folder1/folder2/file1"});
+ }
+
+ public void testDeleteFolder() throws CoreException {
+ // Create a project with dummy sync info
+ IProject project = createProject(new String[] {"folder1/folder2/file1", "folder1/folder2/file2"});
+
+ // Delete the folder and assert old sync info is still in place and new has no sync info
+ IFolder folder = project.getFolder("folder1/folder2/");
+ folder.delete(false, false, null);
+ assertHasSyncInfo(project, new String[] {"folder1/folder2/file1", "folder1/folder2/file2"});
+ }
+
+ public void testMoveFile() throws CoreException {
+ // Create a project with dummy sync info
+ IProject project = createProject(new String[] {"folder1/folder2/file1", "folder1/folder2/file2"});
+
+ // Move the file and assert old sync info is still in place and new has no sync info
+ IFile file = project.getFile("folder1/folder2/file1");
+ project.getFolder("folder1/folder3/").create(false, true, null);
+ file.move(project.getFolder("folder1/folder3/file1").getFullPath(), false, null);
+ assertHasSyncInfo(project, new String[] {"folder1/folder2/file1"});
+ assertHasNoSyncInfo(project, new String[] {"folder1/folder3"});
+ }
+
+ public void testMoveFolder() throws CoreException {
+ // Create a project with dummy sync info
+ IProject project = createProject(new String[] {"folder1/folder2/file1"});
+
+ // Move the folder and assert old sync info is still in place and new has no sync info
+ IFolder folder = project.getFolder("folder1/folder2/");
+ folder.move(project.getFolder("folder1/folder3").getFullPath(), false, null);
+ assertHasSyncInfo(project, new String[] {"folder1/folder2/file1"});
+ assertHasNoSyncInfo(project, new String[] {"folder1/folder3/"});
+ }
+
+ /*
+ * See bug 44446
+ */
+ public void testFileRecreation() throws CoreException {
+ // Create a project with dummy sync info
+ IProject project = createProject(new String[] {"folder1/file1"});
// Remove the file and assert that it still has sync info
+ IFile file = project.getFile("folder1/file1");
file.delete(false, false, null);
- assertNotNull("Sync bytes should not be null for " + file.getFullPath(), sync.getSyncBytes(file));
+ assertHasSyncInfo(file);
// Recreate the file and assert that it still has sync info
file.create(getRandomContents(), false /*force*/, null);
- assertNotNull("Sync bytes should not be null for " + file.getFullPath(), sync.getSyncBytes(file));
+ assertHasSyncInfo(file);
// unmanage the file and assert that sync info is gone
sync.deleteResourceSync(file);
- assertNull("Sync bytes should be null for " + file.getFullPath(), sync.getSyncBytes(file));
-
+ assertHasNoSyncInfo(file);
+ }
+
+ /*
+ * This testcase simulates an update that has an incoming deletion and a merge
+ * (which may do a move).
+ */
+ public void testFileMoveAndDelete() throws CoreException {
+ // Create a project with dummy sync info
+ final IProject project = createProject(new String[] {"folder1/file1", "folder1/file2"});
+
+ sync.run(project, new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ try {
+ IFile file1 = project.getFile("folder1/file1");
+ IFile file2 = project.getFile("folder1/file2");
+ // Delete file 1
+ file1.delete(false, false, null);
+ assertHasSyncInfo(file1);
+ assertHasSyncInfo(file2);
+ sync.deleteResourceSync(file1);
+ assertHasNoSyncInfo(file1);
+ assertHasSyncInfo(file2);
+ // Move file 2
+ file2.move(new Path("file3"), false, false, null);
+ assertHasNoSyncInfo(file1);
+ assertHasSyncInfo(file2);
+ } catch (CoreException e) {
+ throw CVSException.wrapException(e);
+ }
+ }
+ }, null);
+ }
+
+ public void testMoveFolderOverFolder() throws CoreException {
+ // Create a project with dummy sync info
+ final IProject project = createProject(new String[] {"folder1/file1", "folder2/file1"});
+
+ // Change the sync info of folder1/file1 to be revision 1.9
+ String revision = "1.9";
+ IFile file11 = project.getFile("folder1/file1");
+ ResourceSyncInfo info = sync.getResourceSync(file11);
+ MutableResourceSyncInfo muttable = info.cloneMutable();
+ muttable.setRevision(revision);
+ sync.setResourceSync(file11, muttable);
+
+ // Move the folder and verify that the sync info stays
+ project.getFolder("folder2").delete(false, false, null);
+ project.getFolder("folder1").move(new Path("folder2"), false, false, null);
+ assertHasSyncInfo(file11);
+ IFile file21 = project.getFile("folder2/file1");
+ assertHasSyncInfo(file21);
+ assertTrue(sync.getResourceSync(file11).getRevision().equals(revision));
+ assertTrue(!sync.getResourceSync(file21).getRevision().equals(revision));
+
}
}

Back to the top