diff options
author | Michael Valenta | 2002-12-10 21:26:04 +0000 |
---|---|---|
committer | Michael Valenta | 2002-12-10 21:26:04 +0000 |
commit | 6f2e70860d726c7f7b9f2e6b60fbe4de0b3b3209 (patch) | |
tree | 4e81e1f0903c5a5eab4be6e6ac98a618185faf9a | |
parent | ede1996e37992a341d0f9b41309d615c92b536ac (diff) | |
download | eclipse.platform.team-6f2e70860d726c7f7b9f2e6b60fbe4de0b3b3209.tar.gz eclipse.platform.team-6f2e70860d726c7f7b9f2e6b60fbe4de0b3b3209.tar.xz eclipse.platform.team-6f2e70860d726c7f7b9f2e6b60fbe4de0b3b3209.zip |
*** empty log message ***
7 files changed, 471 insertions, 709 deletions
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 458784654..06f9713aa 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 @@ -546,7 +546,7 @@ public class EclipseFile extends EclipseResource implements ICVSFile { * Flush all cached info for the file and it's ancestors */ protected void flushModificationCache() throws CVSException { - EclipseSynchronizer.getInstance().flushModificationCache(getIFile()); + EclipseSynchronizer.getInstance().flushModificationCache(getIFile(), IResource.DEPTH_ZERO); } } 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 9a9220ce8..eb1b47592 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 @@ -126,10 +126,8 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { * Method folderCreated. */ protected void folderCreated() throws CVSException { - Integer count = EclipseSynchronizer.getInstance().getDirtyCount((IContainer)getIResource()); - if (count != null) { - flushWithAncestors(); - } + // flush the dirty cache for the ancestors + flushWithAncestors(); EclipseSynchronizer.getInstance().folderCreated((IFolder)getIResource()); } @@ -218,14 +216,14 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { setSyncInfo(new ResourceSyncInfo(getName())); // if the sync info changed from null, we may need to adjust the ancestors if (oldInfo == null) { - Integer count = synchronizer.getDirtyCount((IContainer)getIResource()); - if (count == null) { + int count = synchronizer.getDirtyCount((IContainer)getIResource()); + if (count == -1) { // There was no cached count. Flush the ancestors so they are recalculated flushWithAncestors(); } else { // There is a count. Decrement the parent's count if the count is zero. // Otherwise, the receiver and it's parents remain dirty. - if (count.intValue() == 0) { + if (count == 0) { synchronizer.setDirtyIndicator(getIResource(), EclipseSynchronizer.NOT_DIRTY_INDICATOR); ((EclipseFolder)getParent()).adjustModifiedCount(false); } @@ -265,13 +263,13 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { monitor.beginTask(null, 10); monitor.subTask(container.getFullPath().toOSString()); EclipseSynchronizer.getInstance().deleteFolderSync(container); - EclipseSynchronizer.getInstance().flushModificationCache(container); + EclipseSynchronizer.getInstance().flushModificationCache(container, IResource.DEPTH_ZERO); IResource[] members = container.members(true); for (int i = 0; i < members.length; i++) { monitor.worked(1); IResource resource = members[i]; if (members[i].getType() == IResource.FILE) { - EclipseSynchronizer.getInstance().flushModificationCache((IFile)resource); + EclipseSynchronizer.getInstance().flushModificationCache(resource, IResource.DEPTH_ZERO); } else { recursiveUnmanage((IContainer) resource, monitor); } @@ -387,7 +385,7 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { * Flush all cached info for the container and it's ancestors */ protected void flushModificationCache() throws CVSException { - EclipseSynchronizer.getInstance().flushModificationCache((IContainer)getIResource()); + EclipseSynchronizer.getInstance().flushModificationCache(getIResource(), IResource.DEPTH_ZERO); } /* @@ -396,8 +394,11 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { */ protected void handleDeletion(IFile file, boolean modified) throws CVSException { boolean adjustParent; - Integer dirtyCount = EclipseSynchronizer.getInstance().getDirtyCount((IContainer)getIResource()); - if (dirtyCount == null) return; + int dirtyCount = EclipseSynchronizer.getInstance().getDirtyCount((IContainer)getIResource()); + if (dirtyCount == -1) { + flushWithAncestors(); + return; + } if (modified) { adjustParent = EclipseSynchronizer.getInstance().addDeletedChild((IContainer)getIResource(), file); } else { @@ -413,8 +414,8 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { // if (isIgnored()) return false; IContainer container = (IContainer)getIResource(); boolean shared = isCVSFolder(); - Integer count = EclipseSynchronizer.getInstance().getDirtyCount(container); - if (count == null) { + int count = EclipseSynchronizer.getInstance().getDirtyCount(container); + if (count == -1) { if (!exists()) return false; String indicator = EclipseSynchronizer.getInstance().getDirtyIndicator(container); if (indicator == null) { @@ -428,12 +429,12 @@ class EclipseFolder extends EclipseResource implements ICVSFolder { EclipseSynchronizer.getInstance().setDirtyCount(container, 0); } else { // The folder is dirty - indicator = determineDirtyCount(indicator, shared); + //indicator = determineDirtyCount(indicator, shared); } } return indicator == EclipseSynchronizer.IS_DIRTY_INDICATOR; } else { - return isModified(count.intValue(), shared); + return isModified(count, shared); } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipsePhantomSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipsePhantomSynchronizer.java deleted file mode 100644 index b1b1979fc..000000000 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipsePhantomSynchronizer.java +++ /dev/null @@ -1,450 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2002 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v0.5 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v05.html - * - * Contributors: - * IBM - Initial API and implementation - ******************************************************************************/ -package org.eclipse.team.internal.ccvs.core.resources; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ISynchronizer; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.team.internal.ccvs.core.CVSException; -import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; -import org.eclipse.team.internal.ccvs.core.ICVSFolder; -import org.eclipse.team.internal.ccvs.core.ICVSResource; -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.SyncFileWriter; - -/** - * Wraps the CVS EclipseSynchronizer with phantoms for folder deletions. - */ -public class EclipsePhantomSynchronizer extends EclipseSynchronizer { - - private static final QualifiedName FOLDER_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-sync"); //$NON-NLS-1$ - private static final QualifiedName RESOURCE_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "resource-sync"); //$NON-NLS-1$ - - EclipsePhantomSynchronizer() { - // Add the sync keys to the workspace synchronizer which is used to handle folder deletions - getWorkspaceSynchronizer().add(FOLDER_SYNC_KEY); - getWorkspaceSynchronizer().add(RESOURCE_SYNC_KEY); - getWorkspaceSynchronizer().add(DIRTY_COUNT); - } - - /** - * Notify the receiver that a folder has been created. - * Any existing phantom sync info will be moved - * - * @param folder the folder that has been created - */ - public void folderCreated(IFolder folder) throws CVSException { - try { - // set the dirty count using what was cached in the phantom it - beginOperation(null); - FolderSyncInfo folderInfo = getPhantomFolderSyncInfo(folder); - if (folderInfo != null) { - Map map = getPhantomResourceSyncInfoMap(folder); - if (folder.getFolder(SyncFileWriter.CVS_DIRNAME).exists()) { - // There is already a CVS subdirectory which indicates that - // either the folder was recreated by an external tool or that - // a folder with CVS information was copied from another location. - // To know the difference, we need to compare the folder sync info. - // If they are mapped to the same root and repository then just - // purge the phantom info. Otherwise, keep the original sync info. - - // flush the phantom info so we can get what is on disk. - flushPhantomInfo(folder); - - // Get the new folder sync info - FolderSyncInfo newFolderInfo = getFolderSync(folder); - if (newFolderInfo.getRoot().equals(folderInfo.getRoot()) - && newFolderInfo.getRepository().equals(folderInfo.getRepository())) { - // The folder is the same so use what is on disk - return; - } - - // The folder is mapped to a different location. - // Purge new resource sync before restoring from phantom - ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(folder); - ICVSResource[] children = cvsFolder.members(ICVSFolder.MANAGED_MEMBERS); - for (int i = 0; i < children.length; i++) { - ICVSResource resource = children[i]; - deleteResourceSync(resource.getIResource()); - } - } - - // set the sync info using what was cached in the phantom - setFolderSync(folder, folderInfo); - for (Iterator it = map.values().iterator(); it.hasNext();) { - ResourceSyncInfo info = (ResourceSyncInfo) it.next(); - IPath path = new Path(info.getName()); - IResource childResource; - if(info.isDirectory()) { - childResource = folder.getFolder(path); - } else { - childResource = folder.getFile(path); - } - setResourceSync(childResource, info); - } - } - } finally { - try { - endOperation(null); - } finally { - flushPhantomInfo(folder); - } - } - } - - /** - * Return the cached folder sync info for the given container or null - * if there is none. - */ - private FolderSyncInfo getPhantomFolderSyncInfo(IContainer container) throws CVSException { - try { - byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(FOLDER_SYNC_KEY, container); - if (bytes == null) return null; - return getFolderSyncInfo(bytes); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - private Map getPhantomResourceSyncInfoMap(IContainer container) throws CVSException { - try { - byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(RESOURCE_SYNC_KEY, container); - if (bytes == null) return new HashMap(); - return getResourceSyncInfoMap(bytes); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Flush any info cahced for the folder - */ - private void flushPhantomInfo(IContainer container) throws CVSException { - try { - if (container.exists() || container.isPhantom()) { - getWorkspaceSynchronizer().flushSyncInfo(FOLDER_SYNC_KEY, container, IResource.DEPTH_ZERO); - } - if (container.exists() || container.isPhantom()) { - getWorkspaceSynchronizer().flushSyncInfo(RESOURCE_SYNC_KEY, container, IResource.DEPTH_ZERO); - } - internalFlushModificationCache(container); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** - * Return the Eclipse Workspace Synchronizer (from org.eclipse.core.resources) - */ - private ISynchronizer getWorkspaceSynchronizer() { - return ResourcesPlugin.getWorkspace().getSynchronizer(); - } - - /** - * The folder is about to be deleted so move the folder's CVS information - * to the workspace synchronizer so it will survive the deletion - */ - public void prepareForDeletion(IContainer container) throws CVSException { - try { - beginOperation(null); - super.prepareForDeletion(container); - if (container.getType() != IResource.PROJECT) { - // Move the dirty count into phantom space - Integer dirtyCount = getDirtyCount(container); - if (dirtyCount != null) { - internalSetDirtyCount(container, dirtyCount.intValue()); - } - } - } finally { - endOperation(null); - } - } - - /** - * Return a map of resource name to ResourceSyncInfo - * - * This should only be used on folders that exist in the workspace - */ - private Map getResourceSyncInfosForChildren(IContainer parent) throws CVSException { - ICVSFolder folder = CVSWorkspaceRoot.getCVSFolderFor(parent); - ICVSResource[] files = folder.members(ICVSFolder.FILE_MEMBERS | ICVSFolder.FOLDER_MEMBERS | ICVSFolder.MANAGED_MEMBERS); - Map result = new HashMap(); - for (int i = 0; i < files.length; i++) { - ICVSResource resource = files[i]; - result.put(resource.getName(), resource.getSyncInfo()); - } - return result; - } - - /** - * Convert a byte array that was created using getBytes(FolderSyncInfo) - * into a FolderSyncInfo - */ - private static FolderSyncInfo getFolderSyncInfo(byte[] bytes) throws CVSException { - ByteArrayInputStream in = new ByteArrayInputStream(bytes); - DataInputStream dis = new DataInputStream(in); - String root; - String repository; - CVSEntryLineTag tag; - boolean isStatic; - try { - root = dis.readUTF(); - repository = dis.readUTF(); - String tagName = dis.readUTF(); - if (tagName.length() == 0) { - tag = null; - } else { - tag = new CVSEntryLineTag(tagName); - } - isStatic = dis.readBoolean(); - } catch (IOException e) { - throw CVSException.wrapException(e); - } - return new FolderSyncInfo(repository, root, tag, isStatic); - } - - /** - * Convert a FolderSyncInfo into a byte array that can be stored - * in the workspace synchronizer - */ - private static byte[] getBytes(FolderSyncInfo info) throws CVSException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(out); - try { - dos.writeUTF(info.getRoot()); - dos.writeUTF(info.getRepository()); - CVSEntryLineTag tag = info.getTag(); - if (tag == null) { - dos.writeUTF(""); //$NON-NLS-1$ - } else { - dos.writeUTF(tag.toString()); - } - dos.writeBoolean(info.getIsStatic()); - dos.close(); - } catch (IOException e) { - throw CVSException.wrapException(e); - } - return out.toByteArray(); - } - - /** - * Convert a Map of ResourceSyncInfo into a byte array that can be stored - * in the workspace synchronizer - */ - private static byte[] getBytes(Map infos) throws CVSException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(out); - try { - dos.writeInt(infos.size()); - Iterator iter = infos.values().iterator(); - while (iter.hasNext()) { - ResourceSyncInfo info = (ResourceSyncInfo)iter.next(); - dos.writeUTF(info.getEntryLine()); - } - } catch (IOException e) { - throw CVSException.wrapException(e); - } - return out.toByteArray(); - } - - /** - * Convert a byte array that was created using getBytes(Map) - * into a Map of ResourceSyncInfo - */ - private static Map getResourceSyncInfoMap(byte[] bytes) throws CVSException { - ByteArrayInputStream in = new ByteArrayInputStream(bytes); - DataInputStream dis = new DataInputStream(in); - Map result = new HashMap(); - try { - int size = dis.readInt(); - for (int i = 0; i < size; i++) { - ResourceSyncInfo info = new ResourceSyncInfo(dis.readUTF(), null, null); - result.put(info.getName(), info); - } - } catch (IOException e) { - throw CVSException.wrapException(e); - } - return result; - } - - /* - * Return the dirty count for the given folder. For existing folders, the - * dirty count may not have been calculated yet and this method will return - * null in that case. For phantom folders, the dirty count is calculated if - * it does not exist yet. - */ - protected Integer getDirtyCount(IContainer parent) throws CVSException { - if (parent.isPhantom()) { - // get the count from the synchronizer - int count = internalGetDirtyCount(parent); - if (count == -1) { - count = calculateDirtyCountForPhantom(parent); - //setDirtyCount(parent, count); - } - return new Integer(count); - } else { - return super.getDirtyCount(parent); - } - } - - protected int internalGetDirtyCount(IContainer parent) throws CVSException { - try { - byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(DIRTY_COUNT, parent); - if (bytes == null) return -1; - return intFromBytes(bytes); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - protected void setDirtyCount(IContainer container, int count) throws CVSException { - if (container.isPhantom()) { - internalSetDirtyCount(container, count); - } else { - super.setDirtyCount(container, count); - } - } - - protected void internalSetDirtyCount(IContainer container, int count) throws CVSException { - try { - beginOperation(null); - getWorkspaceSynchronizer().setSyncInfo(DIRTY_COUNT, container, getBytes(count)); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } finally { - endOperation(null); - } - } - - /* - * Calculate the dirty count for the given phantom folder, performing any - * necessary calculations on the childen as well - */ - private int calculateDirtyCountForPhantom(IContainer parent) throws CVSException { - ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(parent); - ICVSResource[] children = cvsFolder.members(ICVSFolder.MANAGED_MEMBERS | ICVSFolder.PHANTOM_MEMBERS); - int count = 0; - for (int i = 0; i < children.length; i++) { - ICVSResource resource = children[i]; - if (resource.isFolder()) { - Integer dc = getDirtyCount((IContainer)resource.getIResource()); - if (dc.intValue() > 0) count++; - } else { - // Any non-existant managed files are dirty (outgoing deletion) - count++; - } - } - return count; - } - /* - * Convert an int to a byte array - */ - private byte[] getBytes(int count) { - byte[] result = new byte[4]; - result[0] = (byte)(count & 256); - result[1] = (byte)(count<<8 & 256); - result[1] = (byte)(count<<16 & 256); - result[1] = (byte)(count<<24 & 256); - return result; - } - - /* - * Convert a byte array to an int - */ - private int intFromBytes(byte[] bytes) { - return bytes[0] + (bytes[1]>>8) + (bytes[2]>>16) + (bytes[3]>>24); - } - - /* - * Flush all cached info for the container and it's ancestors - */ - protected void flushModificationCache(IContainer container) throws CVSException { - internalFlushModificationCache(container); - super.flushModificationCache(container); - } - - private void internalFlushModificationCache(IContainer container) throws CVSException { -// if (container.exists() || container.isPhantom()) { -// try { -// getWorkspaceSynchronizer().flushSyncInfo(DIRTY_COUNT, container, IResource.DEPTH_ZERO); -// } catch (CoreException e) { -// throw CVSException.wrapException(e); -// } -// } - } - - /** - * @see org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer#addDeletedChild(org.eclipse.core.resources.IContainer, org.eclipse.core.resources.IFile) - */ - protected boolean addDeletedChild(IContainer container, IFile file) throws CVSException { - if (container.isPhantom()) { -// try { -// beginOperation(null); -// int oldCount = internalGetDirtyCount(container); -// if (oldCount == -1) { -// // there is no cached count so wait until the first query -// // or there was no deleted file -// return false; -// } -// int newCount = calculateDirtyCountForPhantom(container); -// // adjust the parent folder count if the newCount is 1; -// return oldCount == 0 && newCount == 1; -// } finally { -// endOperation(null); -// } - return true; - } else { - return super.addDeletedChild(container, file); - } - } - - /** - * @see org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer#removeDeletedChild(org.eclipse.core.resources.IContainer, org.eclipse.core.resources.IFile) - */ - protected boolean removeDeletedChild(IContainer container, IFile file) throws CVSException { - if (container.isPhantom()) { -// try { -// beginOperation(null); -// int oldCount = internalGetDirtyCount(container); -// if (oldCount == -1 || oldCount == 0) { -// // there is no cached count so wait until the first query -// // or there was no deleted file -// return false; -// } -// int newCount = calculateDirtyCountForPhantom(container); -// // adjust the parent folder count if the newCount is 0; -// return newCount == 0; -// } finally { -// endOperation(null); -// } - return true; - } else { - return super.removeDeletedChild(container, file); - } - } -} 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 dc7abddb1..22456f342 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 @@ -26,7 +26,6 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.QualifiedName; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; import org.eclipse.team.internal.ccvs.core.CVSStatus; @@ -49,24 +48,9 @@ import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter; * @see ResourceSyncInfo * @see FolderSyncInfo */ -public class EclipseSynchronizer { - // the resources plugin synchronizer is used to cache and possibly persist. These - // are keys for storing the sync info. - private static final QualifiedName FOLDER_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-sync"); //$NON-NLS-1$ - private static final QualifiedName RESOURCE_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "resource-sync"); //$NON-NLS-1$ - private static final QualifiedName IGNORE_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-ignore"); //$NON-NLS-1$ - - protected static final QualifiedName IS_DIRTY = new QualifiedName(CVSProviderPlugin.ID, "is-dirty"); - protected static final QualifiedName CLEAN_UPDATE = new QualifiedName(CVSProviderPlugin.ID, "clean-update"); - protected static final QualifiedName DIRTY_COUNT = new QualifiedName(CVSProviderPlugin.ID, "dirty-count"); - protected static final QualifiedName DELETED_CHILDREN = new QualifiedName(CVSProviderPlugin.ID, "deleted"); - protected static final String IS_DIRTY_INDICATOR = "d"; - protected static final String NOT_DIRTY_INDICATOR = "c"; - protected static final String UPDATED_INDICATOR = "u"; - - private 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$ - private static final byte[][] EMPTY_RESOURCE_SYNC_INFOS = new byte[0][0]; +public class EclipseSynchronizer { + protected static final String IS_DIRTY_INDICATOR = LowLevelSyncInfoCache.IS_DIRTY_INDICATOR; + protected static final String NOT_DIRTY_INDICATOR = LowLevelSyncInfoCache.NOT_DIRTY_INDICATOR; // the cvs eclipse synchronizer is a singleton private static EclipseSynchronizer instance; @@ -95,13 +79,13 @@ public class EclipseSynchronizer { */ public static EclipseSynchronizer getInstance() { if(instance==null) { - instance = new EclipsePhantomSynchronizer(); + instance = new EclipseSynchronizer(); } return instance; } - public LowLevelSyncInfoCache getLowLevelCacheFor(IContainer container) { - if (container.isPhantom()) { + public LowLevelSyncInfoCache getLowLevelCacheFor(IResource resource) { + if (resource.isPhantom()) { return synchronizerCache; } else { return sessionPropertyCache; @@ -259,7 +243,7 @@ public class EclipseSynchronizer { * @see #addIgnored */ public String[] getIgnored(IContainer folder) throws CVSException { - if (folder.getType() == IResource.ROOT || ! folder.exists()) return NULL_IGNORES; + if (folder.getType() == IResource.ROOT || ! folder.exists()) return SessionPropertySyncInfoCache.NULL_IGNORES; try { beginOperation(null); return cacheFolderIgnores(folder); @@ -408,7 +392,7 @@ public class EclipseSynchronizer { IStatus status = commitCache(Policy.subMonitorFor(monitor, 7)); // purge from memory too if we were asked to - if (purgeCache) purgeCache(root, deep); + if (purgeCache) sessionPropertyCache.purgeCache(root, deep); // prepare for the operation again if we cut the last one short prepareCache(Policy.subMonitorFor(monitor, 1)); @@ -463,11 +447,11 @@ public class EclipseSynchronizer { synchronizerCache.setCachedResourceSyncForChildren(container, sessionPropertyCache.getCachedResourceSyncForChildren(container)); changedFolders.add(container); // todo -// // Move the dirty count into phantom space -// Integer dirtyCount = getDirtyCount(container); -// if (dirtyCount != null) { -// internalSetDirtyCount(container, dirtyCount.intValue()); -// } + // Move the dirty count into phantom space + int dirtyCount = getDirtyCount(container); + if (dirtyCount != -1) { + synchronizerCache.setCachedDirtyCount(container, dirtyCount); + } } } finally { endOperation(null); @@ -603,32 +587,6 @@ public class EclipseSynchronizer { } /** - * Purges the cache recursively for all resources beneath the container. - * There must not be any pending uncommitted changes. - */ - private static void purgeCache(IContainer container, boolean deep) throws CVSException { - if (! container.exists()) return; - try { - if (container.getType() != IResource.ROOT) { - container.setSessionProperty(RESOURCE_SYNC_KEY, null); - container.setSessionProperty(IGNORE_SYNC_KEY, null); - container.setSessionProperty(FOLDER_SYNC_KEY, null); - } - if(deep) { - IResource[] members = container.members(); - for (int i = 0; i < members.length; i++) { - IResource resource = members[i]; - if (resource.getType() != IResource.FILE) { - purgeCache((IContainer) resource, deep); - } - } - } - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - /** * Returns the resource sync info for the resource; null if none. * Parent must exist and must not be the workspace root. * The resource sync info for the children of the parent container MUST ALREADY BE CACHED. @@ -665,24 +623,24 @@ public class EclipseSynchronizer { */ private void purgeFastCache() throws CVSException { try { + beginOperation(null); if (cacheDirty) { - if (cachedResourceSyncInfos.isEmpty()) { - cachedFolder.setSessionProperty(RESOURCE_SYNC_KEY, EMPTY_RESOURCE_SYNC_INFOS); - } else { - byte[][] newInfos = new byte[cachedResourceSyncInfos.size()][]; + byte[][] newInfos = null; + if (!cachedResourceSyncInfos.isEmpty()) { + newInfos = new byte[cachedResourceSyncInfos.size()][]; int i = 0; for (Iterator iter = cachedResourceSyncInfos.values().iterator(); iter.hasNext();) { ResourceSyncInfo info = (ResourceSyncInfo) iter.next(); newInfos[i++] = info.getBytes(); } - getLowLevelCacheFor(cachedFolder).setCachedResourceSyncForChildren(cachedFolder, newInfos); } + getLowLevelCacheFor(cachedFolder).setCachedResourceSyncForChildren(cachedFolder, newInfos); } cacheDirty = false; cachedFolder = null; cachedResourceSyncInfos = null; - } catch (CoreException e) { - throw CVSException.wrapException(e); + } finally { + endOperation(null); } } @@ -946,17 +904,7 @@ public class EclipseSynchronizer { // for all folders that have a CVS folder, ensure the sync info is cached for (int i = 0; i < folders.length; i++) { IContainer parent = folders[i]; - try { - if (parent.getFolder(new Path(SyncFileWriter.CVS_DIRNAME)).exists()) { - if (parent.getSessionProperty(RESOURCE_SYNC_KEY) == null) - return false; - if (parent.getSessionProperty(FOLDER_SYNC_KEY) == null) - return false; - if (parent.getSessionProperty(IGNORE_SYNC_KEY) == null) - return false; - } - } catch (CoreException e) { - // let future operations surface the error + if (!getLowLevelCacheFor(parent).isSyncInfoLoaded(parent)) { return false; } } @@ -1040,46 +988,11 @@ public class EclipseSynchronizer { } protected void setDirtyIndicator(IResource resource, String indicator) throws CVSException { - if (resource.getType() == IResource.FILE) { - internalSetDirtyIndicator((IFile)resource, indicator); - } else { - internalSetDirtyIndicator((IContainer)resource, indicator); - } + getLowLevelCacheFor(resource).setDirtyIndicator(resource, indicator); } + protected String getDirtyIndicator(IResource resource) throws CVSException { - if (resource.getType() == IResource.FILE) { - return internalGetDirtyIndicator((IFile)resource); - } else { - return internalGetDirtyIndicator((IContainer)resource); - } - } - private void internalSetDirtyIndicator(IFile file, String indicator) throws CVSException { - try { - file.setSessionProperty(IS_DIRTY, indicator); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - private String internalGetDirtyIndicator(IFile file) throws CVSException { - try { - return (String)file.getSessionProperty(IS_DIRTY); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - private void internalSetDirtyIndicator(IContainer container, String indicator) throws CVSException { - try { - container.setPersistentProperty(IS_DIRTY, indicator); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - private String internalGetDirtyIndicator(IContainer container) throws CVSException { - try { - return container.getPersistentProperty(IS_DIRTY); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } + return getLowLevelCacheFor(resource).getDirtyIndicator(resource); } /* @@ -1088,56 +1001,35 @@ public class EclipseSynchronizer { * null in that case. For phantom folders, the dirty count is calculated if * it does not exist yet. */ - protected Integer getDirtyCount(IContainer parent) throws CVSException { - if (!parent.exists()) return null; + protected int getDirtyCount(IContainer container) throws CVSException { try { beginOperation(null); - return (Integer)parent.getSessionProperty(DIRTY_COUNT); - } catch (CoreException e) { - throw CVSException.wrapException(e); + return getLowLevelCacheFor(container).getCachedDirtyCount(container); } finally { endOperation(null); } } protected void setDirtyCount(IContainer container, int count) throws CVSException { - if (!container.exists()) return; try { beginOperation(null); - container.setSessionProperty(DIRTY_COUNT, new Integer(count)); - } catch (CoreException e) { - throw CVSException.wrapException(e); + getLowLevelCacheFor(container).setCachedDirtyCount(container, count); } finally { endOperation(null); } } - - /* - * Mark the given existing file as either modified or clean using a session - * property. Also notify the parent to adjust it's modified count. Do - * nothing if the modified state is already what we want. - */ - protected boolean setModified(IFile file, boolean modified) throws CVSException { - String indicator = modified ? IS_DIRTY_INDICATOR : NOT_DIRTY_INDICATOR; - if (getDirtyIndicator(file) == indicator) return false; - setDirtyIndicator(file, indicator); - return true; - } /* - * Mark the given existing folder as either modified or clean using a - * persistant property. Do nothing if the modified state is already what we - * want. + * Mark the given resource as either modified or clean using a persistant + * property. Do nothing if the modified state is already what we want. + * Return true if the modification state was changed. */ - protected void setModified(IContainer container, boolean modified) throws CVSException { - if (!container.exists()) return; + protected boolean setModified(IResource container, boolean modified) throws CVSException { String indicator = modified ? IS_DIRTY_INDICATOR : NOT_DIRTY_INDICATOR; - // if it's already set, no need to set the property or adjust the parents count - if (indicator.equals(getDirtyIndicator(container))) return; - + if (indicator.equals(getDirtyIndicator(container))) return false; // set the dirty indicator and adjust the parent accordingly setDirtyIndicator(container, indicator); - return; + return true; } /* @@ -1146,9 +1038,9 @@ public class EclipseSynchronizer { */ protected boolean adjustModifiedCount(IContainer container, boolean dirty) throws CVSException { if (container.getType() == IResource.ROOT) return false; - Integer property = getDirtyCount(container); + int count = getDirtyCount(container); boolean updateParent = false; - if (property == null) { + if (count == -1) { // The number of dirty children has not been tallied for this parent. // (i.e. no one has queried this folder yet) if (dirty) { @@ -1168,7 +1060,6 @@ public class EclipseSynchronizer { // property is still acurate. } } else { - int count = property.intValue(); if (dirty) { count++; if (count == 1) { @@ -1194,17 +1085,8 @@ public class EclipseSynchronizer { protected boolean addDeletedChild(IContainer container, IFile file) throws CVSException { try { beginOperation(null); - Set deletedFiles = getDeletedChildren(container); - if (deletedFiles == null) - deletedFiles = new HashSet(); - String fileName = file.getName(); - if (deletedFiles.contains(fileName)) - return false; - deletedFiles.add(fileName); - setDeletedChildren(container, deletedFiles); + getLowLevelCacheFor(container).addDeletedChild(container, file); return true; - } catch (CoreException e) { - throw CVSException.wrapException(e); } finally { endOperation(null); } @@ -1213,18 +1095,8 @@ public class EclipseSynchronizer { protected boolean removeDeletedChild(IContainer container, IFile file) throws CVSException { try { beginOperation(null); - Set deletedFiles = getDeletedChildren(container); - if (deletedFiles == null || deletedFiles.isEmpty()) - return false; - String fileName = file.getName(); - if (!deletedFiles.contains(fileName)) - return false; - deletedFiles.remove(fileName); - if (deletedFiles.isEmpty()) deletedFiles = null; - setDeletedChildren(container, deletedFiles); + getLowLevelCacheFor(container).removeDeletedChild(container, file); return true; - } catch (CoreException e) { - throw CVSException.wrapException(e); } finally { endOperation(null); } @@ -1232,76 +1104,31 @@ public class EclipseSynchronizer { protected void setDeletedChildren(IContainer parent, Set deletedFiles) throws CVSException { if (!parent.exists()) return; - try { - parent.setSessionProperty(DELETED_CHILDREN, deletedFiles); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } - } - - private Set getDeletedChildren(IContainer parent) throws CoreException { - return (Set)parent.getSessionProperty(DELETED_CHILDREN); - } - /* - * Flush all cached info for the container and it's ancestors - */ - protected void flushModificationCache(IContainer container) throws CVSException { - if (container.getType() == IResource.ROOT) return; - if (container.exists()) { - try { - beginOperation(null); - container.setSessionProperty(DIRTY_COUNT, null); - container.setSessionProperty(DELETED_CHILDREN, null); - container.setPersistentProperty(IS_DIRTY, null); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } finally { - endOperation(null); - } - } + sessionPropertyCache.setDeletedChildren(parent, deletedFiles); } - protected void flushModificationCache(IContainer container, int depth) throws CVSException { - if (container.getType() == IResource.ROOT) return; - final CVSException[] exception = new CVSException[] { null }; + protected void flushModificationCache(IResource resource, int depth) throws CVSException { + if (resource.getType() == IResource.ROOT) return; try { - container.accept(new IResourceVisitor() { + final CVSException[] exception = new CVSException[] { null }; + beginOperation(null); + resource.accept(new IResourceVisitor() { public boolean visit(IResource resource) throws CoreException { try { - if (resource.getType() == IResource.FILE) { - flushModificationCache((IFile)resource); - } else { - flushModificationCache((IContainer)resource); - } + getLowLevelCacheFor(resource).flushDirtyCache(resource); } catch (CVSException e) { exception[0] = e; } return true; } }, depth, true); + if (exception[0] != null) { + throw exception[0]; + } } catch (CoreException e) { throw CVSException.wrapException(e); - } - if (exception[0] != null) { - throw exception[0]; - } - } - - /* - * Flush all cached info for - * the file and it's ancestors - */ - protected void flushModificationCache(IFile file) throws CVSException { - if (file.exists()) { - try { - beginOperation(null); - file.setSessionProperty(IS_DIRTY, null); - file.setSessionProperty(CLEAN_UPDATE, null); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } finally { - endOperation(null); - } + } finally { + endOperation(null); } } @@ -1313,26 +1140,10 @@ public class EclipseSynchronizer { * @param mFile */ public void markFileAsUpdated(IFile file) throws CVSException { - try { - file.setSessionProperty(CLEAN_UPDATE, UPDATED_INDICATOR); - } catch (CoreException e) { - throw CVSException.wrapException(e); - } + sessionPropertyCache.markFileAsUpdated(file); } protected boolean contentsChangedByUpdate(IFile file) throws CVSException { - try { - Object indicator = file.getSessionProperty(CLEAN_UPDATE); - boolean updated = false; - if (indicator == UPDATED_INDICATOR) { - // the file was changed due to a clean update (i.e. no local mods) so skip it - file.setSessionProperty(CLEAN_UPDATE, null); - file.setSessionProperty(IS_DIRTY, NOT_DIRTY_INDICATOR); - updated = true; - } - return updated; - } catch (CoreException e) { - throw CVSException.wrapException(e); - } + return sessionPropertyCache.contentsChangedByUpdate(file); } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LowLevelSyncInfoCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LowLevelSyncInfoCache.java index 4c6daa9d9..5ee305be4 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LowLevelSyncInfoCache.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LowLevelSyncInfoCache.java @@ -11,6 +11,8 @@ package org.eclipse.team.internal.ccvs.core.resources; import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.QualifiedName; @@ -25,6 +27,8 @@ import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; */ /*package*/ abstract class LowLevelSyncInfoCache { + // the resources plugin synchronizer is used to cache and possibly persist. These + // are keys for storing the sync info. /*package*/ static final QualifiedName FOLDER_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-sync"); //$NON-NLS-1$ /*package*/ static final QualifiedName RESOURCE_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "resource-sync"); //$NON-NLS-1$ /*package*/ static final QualifiedName IGNORE_SYNC_KEY = new QualifiedName(CVSProviderPlugin.ID, "folder-ignore"); //$NON-NLS-1$ @@ -111,4 +115,32 @@ import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; * @param monitor the progress monitor, may be null */ /*package*/ abstract IStatus commitCache(IProgressMonitor monitor); + + /*package*/ abstract String getDirtyIndicator(IResource resource) throws CVSException; + + /*package*/ abstract void setDirtyIndicator(IResource resource, String indicator) throws CVSException; + + /** + * Return the dirty count for the given folder. For existing folders, the + * dirty count may not have been calculated yet and this method will return + * -1 in that case. + */ + /*package*/ abstract int getCachedDirtyCount(IContainer container) throws CVSException; + + /** + * Set the dirty count for the given container to the given count. + * + * @param container + * @param count + * @throws CVSException + */ + /*package*/ abstract void setCachedDirtyCount(IContainer container, int count) throws CVSException; + + /*package*/ abstract void flushDirtyCache(IResource resource) throws CVSException; + + /*package*/ abstract boolean addDeletedChild(IContainer container, IFile file) throws CVSException; + + /*package*/ abstract boolean removeDeletedChild(IContainer container, IFile file) throws CVSException; + + /*package*/ abstract boolean isSyncInfoLoaded(IContainer parent) 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 2a68a8d31..5c26a50d1 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 @@ -17,11 +17,13 @@ import java.util.List; import java.util.Set; import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Path; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; import org.eclipse.team.internal.ccvs.core.CVSStatus; @@ -35,7 +37,7 @@ import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter; */ /*package*/ class SessionPropertySyncInfoCache extends LowLevelSyncInfoCache { - private static final String[] NULL_IGNORES = new String[0]; + /*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$ private static final byte[][] EMPTY_RESOURCE_SYNC_INFOS = new byte[0][0]; @@ -128,6 +130,7 @@ import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter; * @see #cacheFolderSync */ /*package*/ FolderSyncInfo getCachedFolderSync(IContainer container) throws CVSException { + if (!container.exists()) return null; try { FolderSyncInfo info = (FolderSyncInfo)container.getSessionProperty(FOLDER_SYNC_KEY); if (info == null) { @@ -151,6 +154,7 @@ import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter; * @see #cacheResourceSyncForChildren */ /*package*/ byte[][] getCachedResourceSyncForChildren(IContainer container) throws CVSException { + if (!container.exists()) return EMPTY_RESOURCE_SYNC_INFOS; try { byte[][] infos = (byte[][])container.getSessionProperty(RESOURCE_SYNC_KEY); // todo: move check to caller @@ -189,7 +193,7 @@ import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter; throw CVSException.wrapException(e); } } - + /** * Sets the array of folder ignore patterns for the container, must not be null. * Folder must exist and must not be the workspace root. @@ -338,4 +342,202 @@ import org.eclipse.team.internal.ccvs.core.util.SyncFileWriter; monitor.done(); } } + + /*package*/ void setDirtyIndicator(IResource resource, String indicator) throws CVSException { + if (resource.getType() == IResource.FILE) { + internalSetDirtyIndicator((IFile)resource, indicator); + } else { + internalSetDirtyIndicator((IContainer)resource, indicator); + } + } + /*package*/ String getDirtyIndicator(IResource resource) throws CVSException { + if (resource.getType() == IResource.FILE) { + return internalGetDirtyIndicator((IFile)resource); + } else { + return internalGetDirtyIndicator((IContainer)resource); + } + } + private void internalSetDirtyIndicator(IFile file, String indicator) throws CVSException { + try { + file.setSessionProperty(IS_DIRTY, indicator); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + private String internalGetDirtyIndicator(IFile file) throws CVSException { + try { + return (String)file.getSessionProperty(IS_DIRTY); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + private void internalSetDirtyIndicator(IContainer container, String indicator) throws CVSException { + try { + container.setPersistentProperty(IS_DIRTY, indicator); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + private String internalGetDirtyIndicator(IContainer container) throws CVSException { + try { + return container.getPersistentProperty(IS_DIRTY); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /** + * Return the dirty count for the given folder. For existing folders, the + * dirty count may not have been calculated yet and this method will return + * null in that case. For phantom folders, the dirty count is calculated if + * it does not exist yet. + */ + /*package*/ int getCachedDirtyCount(IContainer container) throws CVSException { + if (!container.exists()) return -1; + try { + Integer dirtyCount = (Integer)container.getSessionProperty(DIRTY_COUNT); + if (dirtyCount == null) { + return -1; + } else { + return dirtyCount.intValue(); + } + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /*package*/ void setCachedDirtyCount(IContainer container, int count) throws CVSException { + if (!container.exists()) return; + try { + container.setSessionProperty(DIRTY_COUNT, new Integer(count)); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /* + * Flush all cached info for the container and it's ancestors + */ + /*package*/ void flushDirtyCache(IResource resource) throws CVSException { + if (resource.exists()) { + try { + if (resource.getType() == IResource.FILE) { + resource.setSessionProperty(IS_DIRTY, null); + resource.setSessionProperty(CLEAN_UPDATE, null); + } else { + resource.setSessionProperty(DIRTY_COUNT, null); + resource.setSessionProperty(DELETED_CHILDREN, null); + resource.setPersistentProperty(IS_DIRTY, null); + } + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + } + + /* + * Add the deleted child and return true if it didn't exist before + */ + /*package*/ boolean addDeletedChild(IContainer container, IFile file) throws CVSException { + try { + Set deletedFiles = getDeletedChildren(container); + if (deletedFiles == null) + deletedFiles = new HashSet(); + String fileName = file.getName(); + if (deletedFiles.contains(fileName)) + return false; + deletedFiles.add(fileName); + setDeletedChildren(container, deletedFiles); + return true; + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /*package*/ boolean removeDeletedChild(IContainer container, IFile file) throws CVSException { + try { + Set deletedFiles = getDeletedChildren(container); + if (deletedFiles == null || deletedFiles.isEmpty()) + return false; + String fileName = file.getName(); + if (!deletedFiles.contains(fileName)) + return false; + deletedFiles.remove(fileName); + if (deletedFiles.isEmpty()) deletedFiles = null; + setDeletedChildren(container, deletedFiles); + return true; + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + protected void setDeletedChildren(IContainer parent, Set deletedFiles) throws CVSException { + if (!parent.exists()) return; + try { + parent.setSessionProperty(DELETED_CHILDREN, deletedFiles); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + private Set getDeletedChildren(IContainer parent) throws CoreException { + if (!parent.exists()) return null; + return (Set)parent.getSessionProperty(DELETED_CHILDREN); + } + + /** + * 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. + * + * @param mFile + */ + /*package*/ void markFileAsUpdated(IFile file) throws CVSException { + try { + file.setSessionProperty(CLEAN_UPDATE, UPDATED_INDICATOR); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /*package*/ boolean contentsChangedByUpdate(IFile file) throws CVSException { + try { + Object indicator = file.getSessionProperty(CLEAN_UPDATE); + boolean updated = false; + if (indicator == UPDATED_INDICATOR) { + // the file was changed due to a clean update (i.e. no local mods) so skip it + file.setSessionProperty(CLEAN_UPDATE, null); + file.setSessionProperty(IS_DIRTY, NOT_DIRTY_INDICATOR); + updated = true; + } + return updated; + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /** + * Method isSyncInfoLoaded returns true if all the sync info for the + * provided resources is loaded into the internal cache. + * + * @param resources + * @param i + * @return boolean + */ + /*package*/ boolean isSyncInfoLoaded(IContainer parent) throws CVSException { + try { + if (parent.getFolder(new Path(SyncFileWriter.CVS_DIRNAME)).exists()) { + if (parent.getSessionProperty(RESOURCE_SYNC_KEY) == null) + return false; + if (parent.getSessionProperty(FOLDER_SYNC_KEY) == null) + return false; + if (parent.getSessionProperty(IGNORE_SYNC_KEY) == null) + return false; + } + } catch (CoreException e) { + // let future operations surface the error + return false; + } + return true; + } } 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 f7e6df847..48f6b681d 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 @@ -17,6 +17,7 @@ import java.io.DataOutputStream; import java.io.IOException; import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; @@ -26,6 +27,8 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.ICVSFolder; +import org.eclipse.team.internal.ccvs.core.ICVSResource; import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; /** @@ -258,4 +261,167 @@ import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; // Nothing needs to be done since the synchronizer is persisted return STATUS_OK; } + + /** + * @see org.eclipse.team.internal.ccvs.core.resources.LowLevelSyncInfoCache#getDirtyIndicator(org.eclipse.core.resources.IResource) + */ + String getDirtyIndicator(IResource resource) throws CVSException { + if (resource.getType() == IResource.FILE) { + // if someone is asking about a non-existant file, it's probably dirty + return IS_DIRTY_INDICATOR; + } else { + int dirtyCount = getCachedDirtyCount((IContainer)resource); + switch (dirtyCount) { + case -1 : + return null; + case 0 : + return NOT_DIRTY_INDICATOR; + default : + return IS_DIRTY_INDICATOR; + } + } + } + /** + * @see org.eclipse.team.internal.ccvs.core.resources.LowLevelSyncInfoCache#setDirtyIndicator(org.eclipse.core.resources.IResource, java.lang.String) + */ + void setDirtyIndicator(IResource resource, String indicator) throws CVSException { + // The count is used as the indicator + } + + /** + * Return the dirty count for the given folder. For existing folders, the + * dirty count may not have been calculated yet and this method will return + * null in that case. For phantom folders, the dirty count is calculated if + * it does not exist yet. + */ + /*package*/ int getCachedDirtyCount(IContainer container) throws CVSException { + // get the count from the synchronizer + int count = internalGetDirtyCount(container); + if (count == -1) { + count = calculateDirtyCountForPhantom(container); + //setDirtyCount(parent, count); + } + return count; + } + + /** + * Set the dirty count for the given container to the given count. + * + * @param container + * @param count + * @throws CVSException + */ + /*package*/ void setCachedDirtyCount(IContainer container, int count) throws CVSException { + try { + getWorkspaceSynchronizer().setSyncInfo(DIRTY_COUNT, container, getBytes(count)); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /* + * Convert an int to a byte array + */ + private byte[] getBytes(int count) { + byte[] result = new byte[4]; + result[0] = (byte)(count & 256); + result[1] = (byte)(count<<8 & 256); + result[1] = (byte)(count<<16 & 256); + result[1] = (byte)(count<<24 & 256); + return result; + } + + /* + * Convert a byte array to an int + */ + private int intFromBytes(byte[] bytes) { + return bytes[0] + (bytes[1]>>8) + (bytes[2]>>16) + (bytes[3]>>24); + } + + private int internalGetDirtyCount(IContainer parent) throws CVSException { + try { + byte[] bytes = getWorkspaceSynchronizer().getSyncInfo(DIRTY_COUNT, parent); + if (bytes == null) return -1; + return intFromBytes(bytes); + } catch (CoreException e) { + throw CVSException.wrapException(e); + } + } + + /* + * Calculate the dirty count for the given phantom folder, performing any + * necessary calculations on the childen as well + */ + private int calculateDirtyCountForPhantom(IContainer parent) throws CVSException { + ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(parent); + ICVSResource[] children = cvsFolder.members(ICVSFolder.MANAGED_MEMBERS | ICVSFolder.PHANTOM_MEMBERS); + int count = 0; + for (int i = 0; i < children.length; i++) { + ICVSResource resource = children[i]; + if (resource.isFolder()) { + int dc = getCachedDirtyCount((IContainer)resource.getIResource()); + if (dc > 0) count++; + } else { + // Any non-existant managed files are dirty (outgoing deletion) + count++; + } + } + return count; + } + + /*package*/ void flushDirtyCache(IResource container) throws CVSException { +// if (container.exists() || container.isPhantom()) { +// try { +// getWorkspaceSynchronizer().flushSyncInfo(DIRTY_COUNT, container, IResource.DEPTH_ZERO); +// } catch (CoreException e) { +// throw CVSException.wrapException(e); +// } +// } + } + + /** + * @see org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer#addDeletedChild(org.eclipse.core.resources.IContainer, org.eclipse.core.resources.IFile) + */ + protected boolean addDeletedChild(IContainer container, IFile file) throws CVSException { +// try { +// beginOperation(null); +// int oldCount = internalGetDirtyCount(container); +// if (oldCount == -1) { +// // there is no cached count so wait until the first query +// // or there was no deleted file +// return false; +// } +// int newCount = calculateDirtyCountForPhantom(container); +// // adjust the parent folder count if the newCount is 1; +// return oldCount == 0 && newCount == 1; +// } finally { +// endOperation(null); +// } + return true; + } + + /** + * @see org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer#removeDeletedChild(org.eclipse.core.resources.IContainer, org.eclipse.core.resources.IFile) + */ + protected boolean removeDeletedChild(IContainer container, IFile file) throws CVSException { +// try { +// beginOperation(null); +// int oldCount = internalGetDirtyCount(container); +// if (oldCount == -1 || oldCount == 0) { +// // there is no cached count so wait until the first query +// // or there was no deleted file +// return false; +// } +// int newCount = calculateDirtyCountForPhantom(container); +// // adjust the parent folder count if the newCount is 0; +// return newCount == 0; +// } finally { +// endOperation(null); +// } + return true; + } + + /*package*/ boolean isSyncInfoLoaded(IContainer parent) throws CVSException { + return true; + } } |