diff options
14 files changed, 770 insertions, 567 deletions
diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/AbstractResourceVariantTree.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/AbstractResourceVariantTree.java new file mode 100644 index 000000000..c2a47c453 --- /dev/null +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/AbstractResourceVariantTree.java @@ -0,0 +1,294 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.internal.core.subscribers.caches; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.team.core.TeamException; +import org.eclipse.team.core.synchronize.IResourceVariant; +import org.eclipse.team.internal.core.Assert; +import org.eclipse.team.internal.core.Policy; + + +/** + * This class provides the logic for refreshing and collecting the changes in + * a resource variant tree. + */ +public abstract class AbstractResourceVariantTree implements IResourceVariantTree { + + /** + * Refreshes the resource variant tree for the specified resources and possibly their descendants, + * depending on the depth. The default implementation of this method invokes + * <code>refresh(IResource, int, IProgressMonitor)</code> for each resource. + * Subclasses may override but should either invoke the above mentioned refresh or + * <code>collectChanges</code> in order to reconcile the resource variant tree. + * @param resources the resources whose variants should be refreshed + * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>, + * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>) + * @param monitor a progress monitor + * @return the array of resources whose corresponding varianst have changed + * @throws TeamException + */ + public IResource[] refresh(IResource[] resources, int depth, IProgressMonitor monitor) throws TeamException { + List changedResources = new ArrayList(); + monitor.beginTask(null, 100 * resources.length); + for (int i = 0; i < resources.length; i++) { + IResource resource = resources[i]; + IResource[] changed = refresh(resource, depth, Policy.subMonitorFor(monitor, 100)); + changedResources.addAll(Arrays.asList(changed)); + } + monitor.done(); + if (changedResources == null) return new IResource[0]; + return (IResource[]) changedResources.toArray(new IResource[changedResources.size()]); + } + + /** + * Helper method invoked from <code>refresh(IResource[], int, IProgressMonitor monitor)</code> + * for each resource. The default implementation performs the following steps: + * <ol> + * <li>obtaine the scheduling rule for the resource + * as returned from <code>getSchedulingRule(IResource)</code>. + * <li>get the resource variant handle corresponding to the local resource by calling + * <code>getRemoteTree</code>. + * <li>pass the local resource and the resource variant handle to <code>collectChanges</code> + * </ol> + * Subclasses may override but should perform roughly the same steps. + * @param resource the resoure being refreshed + * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>, + * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>) + * @param monitor a progress monitor + * @return the resource's whose variants have changed + * @throws TeamException + */ + protected IResource[] refresh(IResource resource, int depth, IProgressMonitor monitor) throws TeamException { + IResource[] changedResources = null; + monitor.beginTask(null, 100); + ISchedulingRule rule = getSchedulingRule(resource); + try { + Platform.getJobManager().beginRule(rule, monitor); + if (!resource.getProject().isAccessible()) { + // The project is closed so silently skip it + return new IResource[0]; + } + + monitor.setTaskName(Policy.bind("SynchronizationCacheRefreshOperation.0", resource.getFullPath().makeRelative().toString())); //$NON-NLS-1$ + + // build the remote tree only if an initial tree hasn't been provided + IResourceVariant tree = fetchVariant(resource, depth, Policy.subMonitorFor(monitor, 70)); + + // update the known remote handles + IProgressMonitor sub = Policy.infiniteSubMonitorFor(monitor, 30); + try { + sub.beginTask(null, 64); + changedResources = collectChanges(resource, tree, depth, sub); + } finally { + sub.done(); + } + } finally { + Platform.getJobManager().endRule(rule); + monitor.done(); + } + if (changedResources == null) return new IResource[0]; + return changedResources; + } + + /** + * Return the scheduling rule that should be obtained for the given resource. + * This method is invoked from <code>refresh(IResource, int, IProgressMonitor)</code>. + * By default, the resource's project is returned. Subclasses may override. + * @param resource the resource being refreshed + * @return a scheduling rule or <code>null</code> + */ + protected ISchedulingRule getSchedulingRule(IResource resource) { + return resource.getProject(); + } + + /** + * Collect the changes in the remote tree to the specified depth. + * @param local the local resource being refreshed + * @param remote the corresponding resource variant + * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>, + * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>) + * @param monitor a progress monitor + * @return the resource's whose variants have changed + * @throws TeamException + */ + protected IResource[] collectChanges(IResource local, IResourceVariant remote, int depth, IProgressMonitor monitor) throws TeamException { + List changedResources = new ArrayList(); + collectChanges(local, remote, changedResources, depth, monitor); + return (IResource[]) changedResources.toArray(new IResource[changedResources.size()]); + } + + /** + * Fetch the members of the given resource variant handle. This method may + * return members that were fetched when <code>getRemoteTree</code> was called or + * may fetch the children directly. + * @param variant the resource variant + * @param progress a progress monitor + * @return the members of the resource variant. + */ + protected abstract IResourceVariant[] fetchMembers(IResourceVariant variant, IProgressMonitor progress) throws TeamException; + + /** + * Fetch the resource variant corresponding to the given resource. + * The depth + * parameter indicates the depth of the refresh operation and also indicates the + * depth to which the resource variant's desendants will be traversed. + * This method may prefetch the descendants to the provided depth + * or may just return the variant handle corresponding to the given + * local resource, in which case + * the descendant variants will be fetched by <code>fecthMembers(IResourceVariant, IProgressMonitor)</code>. + * @param resource the local resource + * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>, + * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>) + * @param monitor a progress monitor + * @return the resource variant corresponding to the given local resource + */ + protected abstract IResourceVariant fetchVariant(IResource resource, int depth, IProgressMonitor monitor) throws TeamException; + + private void collectChanges(IResource local, IResourceVariant remote, Collection changedResources, int depth, IProgressMonitor monitor) throws TeamException { + boolean changed = setVariant(local, remote); + if (changed) { + changedResources.add(local); + } + if (depth == IResource.DEPTH_ZERO) return; + Map children = mergedMembers(local, remote, monitor); + for (Iterator it = children.keySet().iterator(); it.hasNext();) { + IResource localChild = (IResource) it.next(); + IResourceVariant remoteChild = (IResourceVariant)children.get(localChild); + collectChanges(localChild, remoteChild, changedResources, + depth == IResource.DEPTH_INFINITE ? IResource.DEPTH_INFINITE : IResource.DEPTH_ZERO, + monitor); + } + + IResource[] cleared = collectedMembers(local, (IResource[]) children.keySet().toArray(new IResource[children.keySet().size()])); + changedResources.addAll(Arrays.asList(cleared)); + } + + /** + * Method that is invoked during collection to let subclasses know which memebers + * were collected for the given resource. Implementors should purge any cached + * state for children of the local resource that are no longer members. any such resources + * should be returned. + * @param local the local resource + * @param members the collected members + * @return any resources that were previously collected whose state has been flushed + */ + protected abstract IResource[] collectedMembers(IResource local, IResource[] members) throws TeamException; + + /** + * Set the variant associated with the local resource to the newly fetched resource + * variant. + * This method is invoked during change collection and should return whether + * the variant associated with the lcoal resource has changed + * @param local the local resource + * @param remote the newly fetched resoure variant + * @return <code>true</code> if the resource variant changed + * @throws TeamException + */ + protected abstract boolean setVariant(IResource local, IResourceVariant remote) throws TeamException; + + private Map mergedMembers(IResource local, IResourceVariant remote, IProgressMonitor progress) throws TeamException { + + // {IResource -> IResourceVariant} + Map mergedResources = new HashMap(); + + IResourceVariant[] remoteChildren; + if (remote == null) { + remoteChildren = new IResourceVariant[0]; + } else { + remoteChildren = fetchMembers(remote, progress); + } + + + IResource[] localChildren = members(local); + + if (remoteChildren.length > 0 || localChildren.length > 0) { + Set allSet = new HashSet(20); + Map localSet = null; + Map remoteSet = null; + + if (localChildren.length > 0) { + localSet = new HashMap(10); + for (int i = 0; i < localChildren.length; i++) { + IResource localChild = localChildren[i]; + String name = localChild.getName(); + localSet.put(name, localChild); + allSet.add(name); + } + } + + if (remoteChildren.length > 0) { + remoteSet = new HashMap(10); + for (int i = 0; i < remoteChildren.length; i++) { + IResourceVariant remoteChild = remoteChildren[i]; + String name = remoteChild.getName(); + remoteSet.put(name, remoteChild); + allSet.add(name); + } + } + + Iterator e = allSet.iterator(); + while (e.hasNext()) { + String keyChildName = (String) e.next(); + + if (progress != null) { + if (progress.isCanceled()) { + throw new OperationCanceledException(); + } + // XXX show some progress? + } + + IResource localChild = + localSet != null ? (IResource) localSet.get(keyChildName) : null; + + IResourceVariant remoteChild = + remoteSet != null ? (IResourceVariant) remoteSet.get(keyChildName) : null; + + if (localChild == null) { + // there has to be a remote resource available if we got this far + Assert.isTrue(remoteChild != null); + boolean isContainer = remoteChild.isContainer(); + localChild = getResourceChild(local /* parent */, keyChildName, isContainer); + } + mergedResources.put(localChild, remoteChild); + } + } + return mergedResources; + } + + private IResource getResourceChild(IResource parent, String childName, boolean isContainer) { + if (parent.getType() == IResource.FILE) { + return null; + } + if (isContainer) { + return ((IContainer) parent).getFolder(new Path(childName)); + } else { + return ((IContainer) parent).getFile(new Path(childName)); + } + } + +} diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/IResourceVariantTree.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/IResourceVariantTree.java index 5bbfbd1b0..cf8c6fcfe 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/IResourceVariantTree.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/IResourceVariantTree.java @@ -34,6 +34,8 @@ public interface IResourceVariantTree { public abstract IResourceVariant getResourceVariant(IResource resource) throws TeamException; + public boolean hasResourceVariant(IResource resource) throws TeamException; + /** * Refreshes the resource variant tree for the specified resources and possibly * their descendants, depending on the depth. diff --git a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/ResourceVariantTree.java b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/ResourceVariantTree.java index dd72c87f4..e9747b065 100644 --- a/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/ResourceVariantTree.java +++ b/bundles/org.eclipse.team.core/src/org/eclipse/team/internal/core/subscribers/caches/ResourceVariantTree.java @@ -10,16 +10,15 @@ *******************************************************************************/ package org.eclipse.team.internal.core.subscribers.caches; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.*; -import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.core.runtime.CoreException; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.synchronize.IResourceVariant; -import org.eclipse.team.internal.core.Assert; -import org.eclipse.team.internal.core.Policy; /** * This class provides the logic for refreshing a resource variant tree that @@ -29,7 +28,7 @@ import org.eclipse.team.internal.core.Policy; * a <code>ResourceVariantByteStore</code>. It also accumulates and returns all local resources * for which the corresponding resource variant has changed. */ -public abstract class ResourceVariantTree implements IResourceVariantTree { +public abstract class ResourceVariantTree extends AbstractResourceVariantTree { /* (non-Javadoc) * @see org.eclipse.team.internal.core.subscribers.caches.IResourceVariantTree#members(org.eclipse.core.resources.IResource) @@ -38,118 +37,29 @@ public abstract class ResourceVariantTree implements IResourceVariantTree { return getByteStore().members(resource); } - /** - * Refreshes the resource variant tree for the specified resources and possibly their descendants, - * depending on the depth. The default implementation of this method invokes - * <code>refresh(IResource, int, IProgressMonitor)</code> for each resource. - * Subclasses may override but should either invoke the above mentioned refresh or - * <code>collectChanges</code> in order to reconcile the resource variant tree. - * @param resources the resources whose variants should be refreshed - * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>, - * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>) - * @param monitor a progress monitor - * @return the array of resources whose corresponding varianst have changed - * @throws TeamException - */ - public IResource[] refresh(IResource[] resources, int depth, IProgressMonitor monitor) throws TeamException { - List changedResources = new ArrayList(); - monitor.beginTask(null, 100 * resources.length); - for (int i = 0; i < resources.length; i++) { - IResource resource = resources[i]; - IResource[] changed = refresh(resource, depth, Policy.subMonitorFor(monitor, 100)); - changedResources.addAll(Arrays.asList(changed)); - } - monitor.done(); - if (changedResources == null) return new IResource[0]; - return (IResource[]) changedResources.toArray(new IResource[changedResources.size()]); - } - - /** - * Helper method invoked from <code>refresh(IResource[], int, IProgressMonitor monitor)</code> - * for each resource. The default implementation performs the following steps: - * <ol> - * <li>obtaine the scheduling rule for the resource - * as returned from <code>getSchedulingRule(IResource)</code>. - * <li>get the resource variant handle corresponding to the local resource by calling - * <code>getRemoteTree</code>. - * <li>pass the local resource and the resource variant handle to <code>collectChanges</code> - * </ol> - * Subclasses may override but should perform roughly the same steps. - * @param resource the resoure being refreshed - * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>, - * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>) - * @param monitor a progress monitor - * @return the resource's whose variants have changed - * @throws TeamException - */ - protected IResource[] refresh(IResource resource, int depth, IProgressMonitor monitor) throws TeamException { - IResource[] changedResources = null; - monitor.beginTask(null, 100); - ISchedulingRule rule = getSchedulingRule(resource); - try { - Platform.getJobManager().beginRule(rule, monitor); - if (!resource.getProject().isAccessible()) { - // The project is closed so silently skip it - return new IResource[0]; - } - - monitor.setTaskName(Policy.bind("SynchronizationCacheRefreshOperation.0", resource.getFullPath().makeRelative().toString())); //$NON-NLS-1$ - - // build the remote tree only if an initial tree hasn't been provided - IResourceVariant tree = fetchVariant(resource, depth, Policy.subMonitorFor(monitor, 70)); - - // update the known remote handles - IProgressMonitor sub = Policy.infiniteSubMonitorFor(monitor, 30); - try { - sub.beginTask(null, 64); - changedResources = collectChanges(resource, tree, depth, sub); - } finally { - sub.done(); - } - } finally { - Platform.getJobManager().endRule(rule); - monitor.done(); - } - if (changedResources == null) return new IResource[0]; - return changedResources; - } - - /** - * Return the scheduling rule that should be obtained for the given resource. - * This method is invoked from <code>refresh(IResource, int, IProgressMonitor)</code>. - * By default, the resource's project is returned. Subclasses may override. - * @param resource the resource being refreshed - * @return a scheduling rule or <code>null</code> + /* (non-Javadoc) + * @see org.eclipse.team.internal.core.subscribers.caches.IResourceVariantTree#hasResourceVariant(org.eclipse.core.resources.IResource) */ - protected ISchedulingRule getSchedulingRule(IResource resource) { - return resource.getProject(); + public boolean hasResourceVariant(IResource resource) throws TeamException { + return getByteStore().getBytes(resource) != null; } - /** - * Collect the changes in the remote tree to the specified depth. - * @param local the local resource being refreshed - * @param remote the corresponding resource variant - * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>, - * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>) - * @param monitor a progress monitor - * @return the resource's whose variants have changed - * @throws TeamException + /* (non-Javadoc) + * @see org.eclipse.team.internal.core.subscribers.caches.AbstractResourceVariantTree#setVariant(org.eclipse.core.resources.IResource, org.eclipse.team.core.synchronize.IResourceVariant) */ - protected IResource[] collectChanges(IResource local, IResourceVariant remote, int depth, IProgressMonitor monitor) throws TeamException { - List changedResources = new ArrayList(); - collectChanges(local, remote, changedResources, depth, monitor); - return (IResource[]) changedResources.toArray(new IResource[changedResources.size()]); + protected boolean setVariant(IResource local, IResourceVariant remote) throws TeamException { + ResourceVariantByteStore cache = getByteStore(); + byte[] newRemoteBytes = getBytes(local, remote); + boolean changed; + if (newRemoteBytes == null) { + changed = cache.deleteBytes(local); + } else { + changed = cache.setBytes(local, newRemoteBytes); + } + return changed; } /** - * Get the byte store that is used to cache the serialization bytes - * for the resource variants of this tree. A byte store is used - * to reduce the memory footprint of the tree. - * @return the resource variant tree that is being refreshed. - */ - protected abstract ResourceVariantByteStore getByteStore(); - - /** * Get the bytes to be stored in the <code>ResourceVariantByteStore</code> * from the given resource variant. * @param local the local resource @@ -157,81 +67,47 @@ public abstract class ResourceVariantTree implements IResourceVariantTree { * @return the bytes for the resource variant. */ protected abstract byte[] getBytes(IResource local, IResourceVariant remote) throws TeamException; - - /** - * Fetch the members of the given resource variant handle. This method may - * return members that were fetched when <code>getRemoteTree</code> was called or - * may fetch the children directly. - * @param variant the resource variant - * @param progress a progress monitor - * @return the members of the resource variant. - */ - protected abstract IResourceVariant[] fetchMembers(IResourceVariant variant, IProgressMonitor progress) throws TeamException; - /** - * Fetch the resource variant corresponding to the given resource. - * The depth - * parameter indicates the depth of the refresh operation and also indicates the - * depth to which the resource variant's desendants will be traversed. - * This method may prefetch the descendants to the provided depth - * or may just return the variant handle corresponding to the given - * local resource, in which case - * the descendant variants will be fetched by <code>fecthMembers(IResourceVariant, IProgressMonitor)</code>. - * @param resource the local resource - * @param depth the depth of the refresh (one of <code>IResource.DEPTH_ZERO</code>, - * <code>IResource.DEPTH_ONE</code>, or <code>IResource.DEPTH_INFINITE</code>) - * @param monitor a progress monitor - * @return the resource variant corresponding to the given local resource + /* (non-Javadoc) + * @see org.eclipse.team.internal.core.subscribers.caches.AbstractResourceVariantTree#collectedMembers(org.eclipse.core.resources.IResource, org.eclipse.core.resources.IResource[]) */ - protected abstract IResourceVariant fetchVariant(IResource resource, int depth, IProgressMonitor monitor) throws TeamException; - - private void collectChanges(IResource local, IResourceVariant remote, Collection changedResources, int depth, IProgressMonitor monitor) throws TeamException { - ResourceVariantByteStore cache = getByteStore(); - byte[] newRemoteBytes = getBytes(local, remote); - boolean changed; - if (newRemoteBytes == null) { - changed = cache.deleteBytes(local); - } else { - changed = cache.setBytes(local, newRemoteBytes); - } - if (changed) { - changedResources.add(local); - } - if (depth == IResource.DEPTH_ZERO) return; - Map children = mergedMembers(local, remote, monitor); - for (Iterator it = children.keySet().iterator(); it.hasNext();) { - IResource localChild = (IResource) it.next(); - IResourceVariant remoteChild = (IResourceVariant)children.get(localChild); - collectChanges(localChild, remoteChild, changedResources, - depth == IResource.DEPTH_INFINITE ? IResource.DEPTH_INFINITE : IResource.DEPTH_ZERO, - monitor); - } - - removeStaleBytes(local, children, changedResources); - } - - private void removeStaleBytes(IResource local, Map children, Collection changedResources) throws TeamException { + protected IResource[] collectedMembers(IResource local, IResource[] members) throws TeamException { // Look for resources that have sync bytes but are not in the resources we care about - ResourceVariantByteStore cache = getByteStore(); - IResource[] resources = getChildrenWithBytes(local); + IResource[] resources = getStoredMembers(local); + List children = new ArrayList(); + List changedResources = new ArrayList(); + children.addAll(Arrays.asList(members)); for (int i = 0; i < resources.length; i++) { IResource resource = resources[i]; - if (!children.containsKey(resource)) { + if (!children.contains(resource)) { // These sync bytes are stale. Purge them - cache.flushBytes(resource, IResource.DEPTH_INFINITE); + flushVariants(resource, IResource.DEPTH_INFINITE); changedResources.add(resource); } } + return (IResource[]) changedResources.toArray(new IResource[changedResources.size()]); } - - /* - * Return all the children of the local resource, including phantoms, that have bytes - * associated with them in the resource varant tree of this operation. - * @param local the local resource - * @return all children that have bytes stored in the tree. + + /** + * Flush any variants for the given resource to the depth specified + * @param resource the local resource + * @param depth the depth of the flush * @throws TeamException */ - private IResource[] getChildrenWithBytes(IResource local) throws TeamException { + private void flushVariants(IResource resource, int depth) throws TeamException { + getByteStore().flushBytes(resource, depth); + } + + /** + * Return all the members of that have resource variant information associated with them, + * such as members that are explicitly flagged as not having a resource variant. This list + * is used by the collection algorithm to flush variants for which there is no local and + * no remote. + * @param local the locla resource + * @return the local children that have resource variant information cached + * @throws TeamException + */ + private IResource[] getStoredMembers(IResource local) throws TeamException { try { if (local.getType() != IResource.FILE && (local.exists() || local.isPhantom())) { // TODO: Not very generic! @@ -252,92 +128,18 @@ public abstract class ResourceVariantTree implements IResourceVariantTree { return new IResource[0]; } - private Map mergedMembers(IResource local, IResourceVariant remote, IProgressMonitor progress) throws TeamException { - - // {IResource -> IResourceVariant} - Map mergedResources = new HashMap(); - - IResourceVariant[] remoteChildren; - if (remote == null) { - remoteChildren = new IResourceVariant[0]; - } else { - remoteChildren = fetchMembers(remote, progress); - } - - - IResource[] localChildren = members(local); - - if (remoteChildren.length > 0 || localChildren.length > 0) { - Set allSet = new HashSet(20); - Map localSet = null; - Map remoteSet = null; - - if (localChildren.length > 0) { - localSet = new HashMap(10); - for (int i = 0; i < localChildren.length; i++) { - IResource localChild = localChildren[i]; - String name = localChild.getName(); - localSet.put(name, localChild); - allSet.add(name); - } - } - - if (remoteChildren.length > 0) { - remoteSet = new HashMap(10); - for (int i = 0; i < remoteChildren.length; i++) { - IResourceVariant remoteChild = remoteChildren[i]; - String name = remoteChild.getName(); - remoteSet.put(name, remoteChild); - allSet.add(name); - } - } - - Iterator e = allSet.iterator(); - while (e.hasNext()) { - String keyChildName = (String) e.next(); - - if (progress != null) { - if (progress.isCanceled()) { - throw new OperationCanceledException(); - } - // XXX show some progress? - } - - IResource localChild = - localSet != null ? (IResource) localSet.get(keyChildName) : null; - - IResourceVariant remoteChild = - remoteSet != null ? (IResourceVariant) remoteSet.get(keyChildName) : null; - - if (localChild == null) { - // there has to be a remote resource available if we got this far - Assert.isTrue(remoteChild != null); - boolean isContainer = remoteChild.isContainer(); - localChild = getResourceChild(local /* parent */, keyChildName, isContainer); - } - mergedResources.put(localChild, remoteChild); - } - } - return mergedResources; - } + /** + * Get the byte store that is used to cache the serialization bytes + * for the resource variants of this tree. A byte store is used + * to reduce the memory footprint of the tree. + * @return the resource variant tree that is being refreshed. + */ + protected abstract ResourceVariantByteStore getByteStore(); - /* - * Create a local resource handle for a resource variant whose - * corresponding local resource was not previously a member of the tree. - * The resource may or may not exist locally. - * @param parent the local parent - * @param childName the name of the local resource - * @param isContainer the type of resource (file or folder) - * @return a local resource handle + /** + * @param project */ - private IResource getResourceChild(IResource parent, String childName, boolean isContainer) { - if (parent.getType() == IResource.FILE) { - return null; - } - if (isContainer) { - return ((IContainer) parent).getFolder(new Path(childName)); - } else { - return ((IContainer) parent).getFile(new Path(childName)); - } + public void removeRoot(IResource resource) throws TeamException { + getByteStore().flushBytes(resource, IResource.DEPTH_INFINITE); } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSCompareSubscriber.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSCompareSubscriber.java index 13e804052..ae44bfb18 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSCompareSubscriber.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSCompareSubscriber.java @@ -14,13 +14,16 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.subscribers.ISubscriberChangeEvent; import org.eclipse.team.core.subscribers.ISubscriberChangeListener; import org.eclipse.team.core.subscribers.SubscriberChangeEvent; -import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantByteStore; +import org.eclipse.team.internal.ccvs.core.syncinfo.CVSResourceVariantTree; +import org.eclipse.team.internal.ccvs.core.syncinfo.MultiTagResourceVariantTree; +import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantTree; import org.eclipse.team.internal.core.subscribers.caches.SessionResourceVariantByteStore; /** @@ -32,51 +35,44 @@ public class CVSCompareSubscriber extends CVSSyncTreeSubscriber implements ISubs public static final String QUALIFIED_NAME = CVSProviderPlugin.ID + ".compare"; //$NON-NLS-1$ private static final String UNIQUE_ID_PREFIX = "compare-"; //$NON-NLS-1$ - private CVSTag tag; - private SessionResourceVariantByteStore remoteByteStore; private IResource[] resources; + private CVSResourceVariantTree tree; public CVSCompareSubscriber(IResource[] resources, CVSTag tag) { super(getUniqueId(), Policy.bind("CVSCompareSubscriber.2", tag.getName()), Policy.bind("CVSCompareSubscriber.3")); //$NON-NLS-1$ //$NON-NLS-2$ this.resources = resources; - this.tag = tag; + tree = new CVSResourceVariantTree(new SessionResourceVariantByteStore(), tag, getCacheFileContentsHint()); + initialize(); + } + + public CVSCompareSubscriber(IProject[] projects, CVSTag[] tags, String name) { + super(getUniqueId(), Policy.bind("CVSCompareSubscriber.2", name), Policy.bind("CVSCompareSubscriber.3")); //$NON-NLS-1$ //$NON-NLS-2$ + this.resources = projects; + MultiTagResourceVariantTree multiTree = new MultiTagResourceVariantTree(new SessionResourceVariantByteStore(), getCacheFileContentsHint()); + for (int i = 0; i < tags.length; i++) { + multiTree.addProject(projects[i], tags[i]); + } initialize(); } private void initialize() { - remoteByteStore = new SessionResourceVariantByteStore(); CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().addListener(this); } public void dispose() { CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().removeListener(this); - remoteByteStore.dispose(); + tree.dispose(); } private static QualifiedName getUniqueId() { String uniqueId = Long.toString(System.currentTimeMillis()); return new QualifiedName(QUALIFIED_NAME, UNIQUE_ID_PREFIX + uniqueId); //$NON-NLS-1$ } - - /* (non-Javadoc) - * @see org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber#getRemoteTag() - */ - protected CVSTag getRemoteTag() { - return tag; - } - - /* (non-Javadoc) - * @see org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber#getBaseTag() - */ - protected CVSTag getBaseTag() { - // No base tag needed since it's a two way compare - return null; - } /* (non-Javadoc) * @see org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber#getBaseSynchronizationCache() */ - protected ResourceVariantByteStore getBaseSynchronizationCache() { + protected ResourceVariantTree getBaseTree() { // No base cache needed since it's a two way compare return null; } @@ -84,8 +80,8 @@ public class CVSCompareSubscriber extends CVSSyncTreeSubscriber implements ISubs /* (non-Javadoc) * @see org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber#getRemoteSynchronizationCache() */ - protected ResourceVariantByteStore getRemoteSynchronizationCache() { - return remoteByteStore; + protected ResourceVariantTree getRemoteTree() { + return tree; } /* (non-Javadoc) @@ -136,6 +132,11 @@ public class CVSCompareSubscriber extends CVSSyncTreeSubscriber implements ISubs if (removedRoot.getFullPath().isPrefixOf(root.getFullPath())) { // The root is no longer managed by CVS removals.add(root); + try { + tree.removeRoot(root); + } catch (TeamException e) { + CVSProviderPlugin.log(e); + } } } if (removals.isEmpty()) { @@ -161,7 +162,7 @@ public class CVSCompareSubscriber extends CVSSyncTreeSubscriber implements ISubs */ public boolean isSupervised(IResource resource) throws TeamException { if (super.isSupervised(resource)) { - if (!resource.exists() && getRemoteSynchronizationCache().getBytes(resource) == null) { + if (!resource.exists() && !getRemoteTree().hasResourceVariant(resource)) { // Exclude conflicting deletions return false; } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSMergeSubscriber.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSMergeSubscriber.java index 500ce8d47..6a38ff1c1 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSMergeSubscriber.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSMergeSubscriber.java @@ -10,21 +10,36 @@ *******************************************************************************/ package org.eclipse.team.internal.ccvs.core; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.QualifiedName; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.core.TeamException; -import org.eclipse.team.core.subscribers.*; -import org.eclipse.team.core.synchronize.*; +import org.eclipse.team.core.subscribers.ISubscriberChangeEvent; +import org.eclipse.team.core.subscribers.ISubscriberChangeListener; +import org.eclipse.team.core.subscribers.SubscriberChangeEvent; +import org.eclipse.team.core.synchronize.IResourceVariant; +import org.eclipse.team.core.synchronize.SyncInfo; +import org.eclipse.team.core.synchronize.SyncInfoFilter; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; import org.eclipse.team.internal.ccvs.core.resources.RemoteFile; -import org.eclipse.team.internal.ccvs.core.syncinfo.CVSSynchronizationCache; +import org.eclipse.team.internal.ccvs.core.syncinfo.CVSResourceVariantTree; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; import org.eclipse.team.internal.ccvs.core.util.Util; -import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantByteStore; import org.eclipse.team.internal.core.subscribers.caches.PersistantResourceVariantByteStore; +import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantTree; /** * A CVSMergeSubscriber is responsible for maintaining the remote trees for a merge into @@ -48,9 +63,8 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour private CVSTag start, end; private List roots; - private CVSSynchronizationCache remoteSynchronizer; private PersistantResourceVariantByteStore mergedSynchronizer; - private CVSSynchronizationCache baseSynchronizer; + private CVSResourceVariantTree baseTree, remoteTree; public CVSMergeSubscriber(IResource[] roots, CVSTag start, CVSTag end) { this(getUniqueId(), roots, start, end); @@ -75,8 +89,10 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour private void initialize() { QualifiedName id = getId(); String syncKeyPrefix = id.getLocalName(); - remoteSynchronizer = new CVSSynchronizationCache(new QualifiedName(SYNC_KEY_QUALIFIER, syncKeyPrefix + end.getName())); - baseSynchronizer = new CVSSynchronizationCache(new QualifiedName(SYNC_KEY_QUALIFIER, syncKeyPrefix + start.getName())); + PersistantResourceVariantByteStore remoteSynchronizer = new PersistantResourceVariantByteStore(new QualifiedName(SYNC_KEY_QUALIFIER, syncKeyPrefix + end.getName())); + remoteTree = new CVSResourceVariantTree(remoteSynchronizer, getRemoteTag(), getCacheFileContentsHint()); + PersistantResourceVariantByteStore baseSynchronizer = new PersistantResourceVariantByteStore(new QualifiedName(SYNC_KEY_QUALIFIER, syncKeyPrefix + start.getName())); + baseTree = new CVSResourceVariantTree(baseSynchronizer, getBaseTag(), getCacheFileContentsHint()); mergedSynchronizer = new PersistantResourceVariantByteStore(new QualifiedName(SYNC_KEY_QUALIFIER, syncKeyPrefix + "0merged")); //$NON-NLS-1$ ResourcesPlugin.getWorkspace().addResourceChangeListener(this); @@ -98,7 +114,7 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour } private void internalMerged(IResource resource) throws TeamException { - byte[] remoteBytes = remoteSynchronizer.getBytes(resource); + byte[] remoteBytes = getRemoteByteStore().getBytes(resource); if (remoteBytes == null) { mergedSynchronizer.deleteBytes(resource); } else { @@ -111,8 +127,8 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour */ public void cancel() { ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); - remoteSynchronizer.dispose(); - baseSynchronizer.dispose(); + remoteTree.dispose(); + baseTree.dispose(); mergedSynchronizer.dispose(); } @@ -127,7 +143,7 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour * @see org.eclipse.team.core.sync.TeamSubscriber#isSupervised(org.eclipse.core.resources.IResource) */ public boolean isSupervised(IResource resource) throws TeamException { - return getBaseSynchronizationCache().getBytes(resource) != null || getRemoteSynchronizationCache().getBytes(resource) != null; + return getBaseTree().hasResourceVariant(resource) || getRemoteTree().hasResourceVariant(resource); } public CVSTag getStartTag() { @@ -192,11 +208,11 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour */ public boolean isMerged(IResource resource) throws TeamException { byte[] mergedBytes = mergedSynchronizer.getBytes(resource); - byte[] remoteBytes = remoteSynchronizer.getBytes(resource); + byte[] remoteBytes = getRemoteByteStore().getBytes(resource); if (mergedBytes == null) { return (remoteBytes == null && mergedSynchronizer.isVariantKnown(resource) - && remoteSynchronizer.isVariantKnown(resource)); + && getRemoteByteStore().isVariantKnown(resource)); } return Util.equals(mergedBytes, remoteBytes); } @@ -238,15 +254,15 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour /* (non-Javadoc) * @see org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber#getBaseSynchronizationCache() */ - protected ResourceVariantByteStore getBaseSynchronizationCache() { - return baseSynchronizer; + protected ResourceVariantTree getBaseTree() { + return baseTree; } /* (non-Javadoc) * @see org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber#getRemoteSynchronizationCache() */ - protected ResourceVariantByteStore getRemoteSynchronizationCache() { - return remoteSynchronizer; + protected ResourceVariantTree getRemoteTree() { + return remoteTree; } protected boolean getCacheFileContentsHint() { @@ -261,7 +277,7 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour List unrefreshed = new ArrayList(); for (int i = 0; i < resources.length; i++) { IResource resource = resources[i]; - if (!baseSynchronizer.isVariantKnown(resource)) { + if (!getBaseByteStore().isVariantKnown(resource)) { unrefreshed.add(resource); } } @@ -301,7 +317,7 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour if (resource.getType() == IResource.FILE) { ICVSFile local = CVSWorkspaceRoot.getCVSFileFor((IFile)resource); byte[] localBytes = local.getSyncBytes(); - byte[] remoteBytes = remoteSynchronizer.getBytes(resource); + byte[] remoteBytes = getRemoteByteStore().getBytes(resource); if (remoteBytes != null && localBytes != null && local.exists() @@ -322,7 +338,7 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour // Use the merged bytes for the base if there are some byte[] mergedBytes = mergedSynchronizer.getBytes(resource); if (mergedBytes != null) { - byte[] parentBytes = baseSynchronizer.getBytes(resource.getParent()); + byte[] parentBytes = getBaseByteStore().getBytes(resource.getParent()); if (parentBytes != null) { return RemoteFile.fromBytes(resource, mergedBytes, parentBytes); } @@ -334,4 +350,18 @@ public class CVSMergeSubscriber extends CVSSyncTreeSubscriber implements IResour } return super.getBaseResource(resource); } + + /* + * TODO: Should not need to access this here + */ + private PersistantResourceVariantByteStore getRemoteByteStore() { + return (PersistantResourceVariantByteStore)((CVSResourceVariantTree)getRemoteTree()).getByteStore(); + } + + /* + * TODO: Should not need to access this here + */ + private PersistantResourceVariantByteStore getBaseByteStore() { + return (PersistantResourceVariantByteStore)((CVSResourceVariantTree)getBaseTree()).getByteStore(); + } }
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSSyncTreeSubscriber.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSSyncTreeSubscriber.java index 4bc1dca7b..fe1865d48 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSSyncTreeSubscriber.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSSyncTreeSubscriber.java @@ -10,17 +10,33 @@ *******************************************************************************/ package org.eclipse.team.internal.ccvs.core; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceStatus; +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.QualifiedName; +import org.eclipse.core.runtime.Status; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.core.TeamException; -import org.eclipse.team.core.subscribers.*; -import org.eclipse.team.core.synchronize.*; -import org.eclipse.team.internal.core.subscribers.caches.*; -import org.eclipse.team.internal.ccvs.core.resources.*; -import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.core.subscribers.SubscriberChangeEvent; +import org.eclipse.team.core.synchronize.IResourceVariant; +import org.eclipse.team.core.synchronize.IResourceVariantComparator; +import org.eclipse.team.core.synchronize.SyncInfo; +import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; +import org.eclipse.team.internal.core.subscribers.caches.PersistantResourceVariantByteStore; +import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantByteStore; +import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantTree; +import org.eclipse.team.internal.core.subscribers.caches.SyncTreeSubscriber; /** * This class provides common funtionality for three way sychronizing @@ -151,28 +167,16 @@ public abstract class CVSSyncTreeSubscriber extends SyncTreeSubscriber { protected IResource[] refreshBase(IResource[] resources, int depth, IProgressMonitor monitor) throws TeamException { if (isThreeWay()) { - return new CVSRefreshOperation(getBaseSynchronizationCache(), null, getBaseTag(), getCacheFileContentsHint()) - .refresh(resources, depth, monitor); + return getBaseTree().refresh(resources, depth, monitor); } else { return new IResource[0]; } } protected IResource[] refreshRemote(IResource[] resources, int depth, IProgressMonitor monitor) throws TeamException { - return new CVSRefreshOperation(getRemoteSynchronizationCache(), getBaseSynchronizationCache(), getRemoteTag(), getCacheFileContentsHint()) - .refresh(resources, depth, monitor); + return getRemoteTree().refresh(resources, depth, monitor); } - /** - * Return the tag associated with the base tree. t is used by the refreshBase method. - */ - protected abstract CVSTag getRemoteTag(); - - /** - * Return the tag associated with the base tree. t is used by the refreshRemote method. - */ - protected abstract CVSTag getBaseTag(); - /* (non-Javadoc) * @see org.eclipse.team.core.sync.ISyncTreeSubscriber#isSupervised(org.eclipse.core.resources.IResource) */ @@ -199,66 +203,26 @@ public abstract class CVSSyncTreeSubscriber extends SyncTreeSubscriber { } public IResourceVariant getRemoteResource(IResource resource) throws TeamException { - return getRemoteResource(resource, getRemoteSynchronizationCache()); + return getRemoteTree().getResourceVariant(resource); } public IResourceVariant getBaseResource(IResource resource) throws TeamException { if (isThreeWay()) { - return getRemoteResource(resource, getBaseSynchronizationCache()); + return getBaseTree().getResourceVariant(resource); } else { return null; } } /** - * Return the synchronization cache that provides access to the base sychronization bytes. + * Return the base resource variant tree. */ - protected abstract ResourceVariantByteStore getBaseSynchronizationCache(); + protected abstract ResourceVariantTree getBaseTree(); /** - * Return the synchronization cache that provides access to the base sychronization bytes. + * Return the remote resource variant tree. */ - protected abstract ResourceVariantByteStore getRemoteSynchronizationCache(); - - public IResourceVariant getRemoteResource(IResource resource, ResourceVariantByteStore cache) throws TeamException { - byte[] remoteBytes = cache.getBytes(resource); - if (remoteBytes == null) { - // There is no remote handle for this resource - return null; - } else { - // TODO: This code assumes that the type of the remote resource - // matches that of the local resource. This may not be true. - if (resource.getType() == IResource.FILE) { - byte[] parentBytes = cache.getBytes(resource.getParent()); - if (parentBytes == null) { - // Before failing, try and use the local folder sync bytes - ICVSFolder local = CVSWorkspaceRoot.getCVSFolderFor(resource.getParent()); - FolderSyncInfo info = local.getFolderSyncInfo(); - if (info == null) { - CVSProviderPlugin.log(new CVSException( - Policy.bind("ResourceSynchronizer.missingParentBytesOnGet", getSyncName(cache).toString(), resource.getFullPath().toString()))); //$NON-NLS-1$ - // Assume there is no remote and the problem is a programming error - return null; - } else { - // Use the folder sync from the workspace and the tag from the file - - byte[] tagBytes = ResourceSyncInfo.getTagBytes(remoteBytes); - CVSTag tag; - if (tagBytes == null || tagBytes.length == 0) { - tag = CVSTag.DEFAULT; - } else { - tag = new CVSEntryLineTag(new String(tagBytes)); - } - FolderSyncInfo newInfo = new FolderSyncInfo(info.getRepository(), info.getRoot(), tag, false); - parentBytes = newInfo.getBytes(); - } - } - return RemoteFile.fromBytes(resource, remoteBytes, parentBytes); - } else { - return RemoteFolder.fromBytes(resource, remoteBytes); - } - } - } + protected abstract ResourceVariantTree getRemoteTree(); private String getSyncName(ResourceVariantByteStore cache) { if (cache instanceof PersistantResourceVariantByteStore) { @@ -271,7 +235,7 @@ public abstract class CVSSyncTreeSubscriber extends SyncTreeSubscriber { * @see org.eclipse.team.core.subscribers.helpers.SyncTreeSubscriber#hasRemote(org.eclipse.core.resources.IResource) */ protected boolean hasRemote(IResource resource) throws TeamException { - return getRemoteSynchronizationCache().getBytes(resource) != null; + return getRemoteTree().hasResourceVariant(resource); } /* (non-Javadoc) @@ -296,9 +260,9 @@ public abstract class CVSSyncTreeSubscriber extends SyncTreeSubscriber { throw e; } } - allMembers.addAll(Arrays.asList(getMembers(getRemoteSynchronizationCache(), resource))); + allMembers.addAll(Arrays.asList(getMembers(getRemoteTree(), resource))); if (isThreeWay()) { - allMembers.addAll(Arrays.asList(getMembers(getBaseSynchronizationCache(), resource))); + allMembers.addAll(Arrays.asList(getMembers(getBaseTree(), resource))); } for (Iterator iterator = allMembers.iterator(); iterator.hasNext();) { IResource member = (IResource) iterator.next(); @@ -316,11 +280,11 @@ public abstract class CVSSyncTreeSubscriber extends SyncTreeSubscriber { } } - private IResource[] getMembers(ResourceVariantByteStore cache, IResource resource) throws TeamException, CoreException { + private IResource[] getMembers(ResourceVariantTree tree, IResource resource) throws TeamException, CoreException { // Filter and return only phantoms associated with the remote synchronizer. IResource[] members; try { - members = cache.members(resource); + members = tree.members(resource); } catch (CoreException e) { if (!isSupervised(resource) || e.getStatus().getCode() == IResourceStatus.RESOURCE_NOT_FOUND) { // The resource is no longer supervised or doesn't exist in any form 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 3fb66fe63..83c67a659 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 @@ -13,8 +13,16 @@ package org.eclipse.team.internal.ccvs.core; import java.util.ArrayList; import java.util.List; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceVisitor; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.QualifiedName; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.subscribers.ISubscriberChangeEvent; @@ -23,19 +31,22 @@ import org.eclipse.team.core.synchronize.IResourceVariant; import org.eclipse.team.core.synchronize.SyncInfo; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer; -import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.CVSBaseResourceVariantTree; +import org.eclipse.team.internal.ccvs.core.syncinfo.CVSDescendantResourceVariantTree; +import org.eclipse.team.internal.ccvs.core.syncinfo.CVSResourceVariantTree; +import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; import org.eclipse.team.internal.ccvs.core.util.ResourceStateChangeListeners; +import org.eclipse.team.internal.core.subscribers.caches.DescendantResourceVariantByteStore; import org.eclipse.team.internal.core.subscribers.caches.PersistantResourceVariantByteStore; import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantByteStore; -import org.eclipse.team.internal.ccvs.core.Policy; +import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantTree; /** * CVSWorkspaceSubscriber */ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IResourceStateChangeListener { - private CVSDescendantSynchronizationCache remoteSynchronizer; - private ResourceVariantByteStore baseSynchronizer; + private CVSResourceVariantTree baseTree, remoteTree; // qualified name for remote sync info private static final String REMOTE_RESOURCE_KEY = "remote-resource-key"; //$NON-NLS-1$ @@ -44,10 +55,12 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe super(id, name, description); // install sync info participant - baseSynchronizer = new CVSBaseSynchronizationCache(); - remoteSynchronizer = new CVSDescendantSynchronizationCache( + ResourceVariantByteStore baseSynchronizer = new CVSBaseResourceVariantTree(); + baseTree = new CVSResourceVariantTree(baseSynchronizer, getBaseTag(), getCacheFileContentsHint()); + CVSDescendantResourceVariantTree remoteSynchronizer = new CVSDescendantResourceVariantTree( baseSynchronizer, new PersistantResourceVariantByteStore(new QualifiedName(SYNC_KEY_QUALIFIER, REMOTE_RESOURCE_KEY))); + remoteTree = new CVSResourceVariantTree(remoteSynchronizer, getRemoteTag(), getCacheFileContentsHint()); ResourceStateChangeListeners.getListener().addResourceStateChangeListener(this); } @@ -84,19 +97,20 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe private void internalResourceSyncInfoChanged(IResource[] changedResources, boolean canModifyWorkspace) { // IMPORTANT NOTE: This will throw exceptions if performed during the POST_CHANGE delta phase!!! + DescendantResourceVariantByteStore remoteByteStore = getRemoteByteStore(); for (int i = 0; i < changedResources.length; i++) { IResource resource = changedResources[i]; try { if (resource.getType() == IResource.FILE && (resource.exists() || resource.isPhantom())) { - byte[] remoteBytes = remoteSynchronizer.getBytes(resource); + byte[] remoteBytes = remoteByteStore.getBytes(resource); if (remoteBytes == null) { - if (remoteSynchronizer.isVariantKnown(resource)) { + if (remoteByteStore.isVariantKnown(resource)) { // The remote is known not to exist. If the local resource is // managed then this information is stale - if (getBaseSynchronizationCache().getBytes(resource) != null) { + if (getBaseTree().hasResourceVariant(resource)) { if (canModifyWorkspace) { - remoteSynchronizer.flushBytes(resource, IResource.DEPTH_ZERO); + remoteByteStore.flushBytes(resource, IResource.DEPTH_ZERO); } else { // The revision comparison will handle the stale sync bytes // TODO: Unless the remote is known not to exist (see bug 52936) @@ -104,19 +118,19 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe } } } else { - byte[] localBytes = baseSynchronizer.getBytes(resource); + byte[] localBytes = getBaseByteStore().getBytes(resource); if (localBytes == null || !isLaterRevision(remoteBytes, localBytes)) { if (canModifyWorkspace) { - remoteSynchronizer.flushBytes(resource, IResource.DEPTH_ZERO); + remoteByteStore.flushBytes(resource, IResource.DEPTH_ZERO); } else { - // The getRemoteResource method handles the stale sync bytes + // The remote byte store handles the stale sync bytes } } } } else if (resource.getType() == IResource.FOLDER) { // If the base has sync info for the folder, purge the remote bytes - if (getBaseSynchronizationCache().getBytes(resource) != null && canModifyWorkspace) { - remoteSynchronizer.flushBytes(resource, IResource.DEPTH_ZERO); + if (getBaseTree().hasResourceVariant(resource) && canModifyWorkspace) { + remoteByteStore.flushBytes(resource, IResource.DEPTH_ZERO); } } } catch (TeamException e) { @@ -168,7 +182,7 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe */ public void projectDeconfigured(IProject project) { try { - remoteSynchronizer.flushBytes(project, IResource.DEPTH_INFINITE); + getRemoteTree().removeRoot(project); } catch (TeamException e) { CVSProviderPlugin.log(e); } @@ -179,7 +193,7 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe public void setRemote(IProject project, IResourceVariant remote, IProgressMonitor monitor) throws TeamException { // TODO: This exposes internal behavior to much IResource[] changedResources = - new CVSRefreshOperation(remoteSynchronizer, baseSynchronizer, null, false).collectChanges(project, remote, IResource.DEPTH_INFINITE, monitor); + ((CVSResourceVariantTree)getRemoteTree()).collectChanges(project, remote, IResource.DEPTH_INFINITE, monitor); if (changedResources.length != 0) { fireTeamResourceChange(SubscriberChangeEvent.asSyncChangedDeltas(this, changedResources)); } @@ -212,15 +226,15 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe /* (non-Javadoc) * @see org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber#getBaseSynchronizationCache() */ - protected ResourceVariantByteStore getBaseSynchronizationCache() { - return baseSynchronizer; + protected ResourceVariantTree getBaseTree() { + return baseTree; } /* (non-Javadoc) * @see org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber#getRemoteSynchronizationCache() */ - protected ResourceVariantByteStore getRemoteSynchronizationCache() { - return remoteSynchronizer; + protected ResourceVariantTree getRemoteTree() { + return remoteTree; } /* (non-Javadoc) @@ -271,7 +285,7 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe } private boolean hasIncomingChange(IResource resource) throws TeamException { - return remoteSynchronizer.isVariantKnown(resource); + return getRemoteByteStore().isVariantKnown(resource); } private boolean hasOutgoingChange(IResource resource, IProgressMonitor monitor) throws CVSException { @@ -294,5 +308,18 @@ public class CVSWorkspaceSubscriber extends CVSSyncTreeSubscriber implements IRe return !folder.isCVSFolder() && !folder.isIgnored(); } } + + /* + * TODO: Should not need to access this here + */ + private CVSDescendantResourceVariantTree getRemoteByteStore() { + return (CVSDescendantResourceVariantTree)((CVSResourceVariantTree)getRemoteTree()).getByteStore(); + } + /* + * TODO: Should not need to access this here + */ + private ResourceVariantByteStore getBaseByteStore() { + return ((CVSResourceVariantTree)getBaseTree()).getByteStore(); + } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSBaseSynchronizationCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSBaseResourceVariantTree.java index b1c615668..0484285cc 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSBaseSynchronizationCache.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSBaseResourceVariantTree.java @@ -17,7 +17,7 @@ import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantByteStor import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer; -public class CVSBaseSynchronizationCache extends ResourceVariantByteStore { +public class CVSBaseResourceVariantTree extends ResourceVariantByteStore { public void dispose() { // Do nothing } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSDescendantSynchronizationCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSDescendantResourceVariantTree.java index 7baefb8cc..3cc2ae128 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSDescendantSynchronizationCache.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSDescendantResourceVariantTree.java @@ -18,9 +18,9 @@ import org.eclipse.team.internal.ccvs.core.*; /** * CVS sycnrhonization cache that ignores stale remote bytes */ -public class CVSDescendantSynchronizationCache extends DescendantResourceVariantByteStore { +public class CVSDescendantResourceVariantTree extends DescendantResourceVariantByteStore { - public CVSDescendantSynchronizationCache(ResourceVariantByteStore baseCache, PersistantResourceVariantByteStore remoteCache) { + public CVSDescendantResourceVariantTree(ResourceVariantByteStore baseCache, PersistantResourceVariantByteStore remoteCache) { super(baseCache, remoteCache); } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSRefreshOperation.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSRefreshOperation.java deleted file mode 100644 index 829a34dd6..000000000 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSRefreshOperation.java +++ /dev/null @@ -1,106 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2003 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.team.internal.ccvs.core.syncinfo; - -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.team.core.TeamException; -import org.eclipse.team.core.synchronize.IResourceVariant; -import org.eclipse.team.internal.ccvs.core.*; -import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; -import org.eclipse.team.internal.ccvs.core.resources.RemoteResource; -import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantByteStore; -import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantTree; - -/** - * CVS Specific refresh operation - */ -public class CVSRefreshOperation extends ResourceVariantTree { - - private ResourceVariantByteStore cache, baseCache; - private CVSTag tag; - private boolean cacheFileContentsHint; - private CVSSyncTreeSubscriber subscriber; - - public CVSRefreshOperation(ResourceVariantByteStore cache, ResourceVariantByteStore baseCache, CVSTag tag, boolean cacheFileContentsHint) { - this.tag = tag; - this.cache = cache; - this.baseCache = cache; - this.cacheFileContentsHint = cacheFileContentsHint; - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.RefreshOperation#getSynchronizationCache() - */ - protected ResourceVariantByteStore getByteStore() { - return cache; - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.RefreshOperation#getRemoteSyncBytes(org.eclipse.core.resources.IResource, org.eclipse.team.core.subscribers.ISubscriberResource) - */ - protected byte[] getBytes(IResource local, IResourceVariant remote) throws TeamException { - if (remote != null) { - return ((RemoteResource)remote).getSyncBytes(); - } else { - if (local.getType() == IResource.FOLDER && baseCache != null) { - // If there is no remote, use the local sync for the folder - return baseCache.getBytes(local); - } - return null; - } - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.RefreshOperation#getRemoteChildren(org.eclipse.team.core.subscribers.ISubscriberResource, org.eclipse.core.runtime.IProgressMonitor) - */ - protected IResourceVariant[] fetchMembers(IResourceVariant remote, IProgressMonitor progress) throws TeamException { - ICVSRemoteResource[] children = remote != null ? (ICVSRemoteResource[])((RemoteResource)remote).members(progress) : new ICVSRemoteResource[0]; - IResourceVariant[] result = new IResourceVariant[children.length]; - for (int i = 0; i < children.length; i++) { - result[i] = (IResourceVariant)children[i]; - } - return result; - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.RefreshOperation#buildRemoteTree(org.eclipse.core.resources.IResource, int, boolean, org.eclipse.core.runtime.IProgressMonitor) - */ - protected IResourceVariant fetchVariant(IResource resource, int depth, IProgressMonitor monitor) throws TeamException { - // TODO: we are currently ignoring the depth parameter because the build remote tree is - // by default deep! - return (IResourceVariant)CVSWorkspaceRoot.getRemoteTree(resource, tag, cacheFileContentsHint, monitor); - } - - /* (non-Javadoc) - * @see org.eclipse.team.internal.core.subscribers.caches.ResourceVariantTreeRefreshOperation#collectChanges(org.eclipse.core.resources.IResource, org.eclipse.team.core.synchronize.IResourceVariant, int, org.eclipse.core.runtime.IProgressMonitor) - */ - public IResource[] collectChanges(IResource local, - IResourceVariant remote, int depth, IProgressMonitor monitor) - throws TeamException { - return super.collectChanges(local, remote, depth, monitor); - } - - /* (non-Javadoc) - * @see org.eclipse.team.internal.core.subscribers.caches.IResourceVariantTree#getRoots() - */ - public IResource[] getRoots() { - return subscriber.roots(); - } - - /* (non-Javadoc) - * @see org.eclipse.team.internal.core.subscribers.caches.IResourceVariantTree#getResourceVariant(org.eclipse.core.resources.IResource) - */ - public IResourceVariant getResourceVariant(IResource resource) throws TeamException { - return subscriber.getRemoteResource(resource, getByteStore()); - } - -} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSResourceVariantTree.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSResourceVariantTree.java new file mode 100644 index 000000000..f9803c0c9 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSResourceVariantTree.java @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.internal.ccvs.core.syncinfo; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.team.core.RepositoryProvider; +import org.eclipse.team.core.TeamException; +import org.eclipse.team.core.synchronize.IResourceVariant; +import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; +import org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber; +import org.eclipse.team.internal.ccvs.core.CVSTag; +import org.eclipse.team.internal.ccvs.core.ICVSFolder; +import org.eclipse.team.internal.ccvs.core.ICVSRemoteResource; +import org.eclipse.team.internal.ccvs.core.Policy; +import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; +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.resources.RemoteResource; +import org.eclipse.team.internal.core.subscribers.caches.PersistantResourceVariantByteStore; +import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantByteStore; +import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantTree; + +/** + * CVS Specific refresh operation + */ +public class CVSResourceVariantTree extends ResourceVariantTree { + + private ResourceVariantByteStore cache; + private CVSTag tag; + private boolean cacheFileContentsHint; + private CVSSyncTreeSubscriber subscriber; + + public CVSResourceVariantTree(ResourceVariantByteStore cache, CVSTag tag, boolean cacheFileContentsHint) { + this.tag = tag; + this.cache = cache; + this.cacheFileContentsHint = cacheFileContentsHint; + } + + /* (non-Javadoc) + * @see org.eclipse.team.core.subscribers.RefreshOperation#getSynchronizationCache() + */ + public ResourceVariantByteStore getByteStore() { + return cache; + } + + /* (non-Javadoc) + * @see org.eclipse.team.core.subscribers.RefreshOperation#getRemoteSyncBytes(org.eclipse.core.resources.IResource, org.eclipse.team.core.subscribers.ISubscriberResource) + */ + protected byte[] getBytes(IResource local, IResourceVariant remote) throws TeamException { + if (remote != null) { + return ((RemoteResource)remote).getSyncBytes(); + } else { + if (local.getType() == IResource.FOLDER) { + // If there is no remote, use the local sync for the folder + return getBaseBytes((IContainer)local, getTag(local)); + } + return null; + } + } + + /* (non-Javadoc) + * @see org.eclipse.team.core.subscribers.RefreshOperation#getRemoteChildren(org.eclipse.team.core.subscribers.ISubscriberResource, org.eclipse.core.runtime.IProgressMonitor) + */ + protected IResourceVariant[] fetchMembers(IResourceVariant remote, IProgressMonitor progress) throws TeamException { + ICVSRemoteResource[] children = remote != null ? (ICVSRemoteResource[])((RemoteResource)remote).members(progress) : new ICVSRemoteResource[0]; + IResourceVariant[] result = new IResourceVariant[children.length]; + for (int i = 0; i < children.length; i++) { + result[i] = (IResourceVariant)children[i]; + } + return result; + } + + /* (non-Javadoc) + * @see org.eclipse.team.core.subscribers.RefreshOperation#buildRemoteTree(org.eclipse.core.resources.IResource, int, boolean, org.eclipse.core.runtime.IProgressMonitor) + */ + protected IResourceVariant fetchVariant(IResource resource, int depth, IProgressMonitor monitor) throws TeamException { + // TODO: we are currently ignoring the depth parameter because the build remote tree is + // by default deep! + return (IResourceVariant)CVSWorkspaceRoot.getRemoteTree(resource, getTag(resource), cacheFileContentsHint, monitor); + } + + /* (non-Javadoc) + * @see org.eclipse.team.internal.core.subscribers.caches.ResourceVariantTreeRefreshOperation#collectChanges(org.eclipse.core.resources.IResource, org.eclipse.team.core.synchronize.IResourceVariant, int, org.eclipse.core.runtime.IProgressMonitor) + */ + public IResource[] collectChanges(IResource local, + IResourceVariant remote, int depth, IProgressMonitor monitor) + throws TeamException { + return super.collectChanges(local, remote, depth, monitor); + } + + /* (non-Javadoc) + * @see org.eclipse.team.internal.core.subscribers.caches.IResourceVariantTree#getRoots() + */ + public IResource[] getRoots() { + return subscriber.roots(); + } + + /* (non-Javadoc) + * @see org.eclipse.team.internal.core.subscribers.caches.IResourceVariantTree#getResourceVariant(org.eclipse.core.resources.IResource) + */ + public IResourceVariant getResourceVariant(IResource resource) throws TeamException { + byte[] remoteBytes = cache.getBytes(resource); + if (remoteBytes == null) { + // There is no remote handle for this resource + return null; + } else { + if (resource.getType() == IResource.FILE) { + byte[] parentBytes = getParentBytes(resource); + if (parentBytes == null) { + IProject project = resource.getProject(); + if (project.exists() && RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId()) != null) { + CVSProviderPlugin.log(new CVSException( + Policy.bind("ResourceSynchronizer.missingParentBytesOnGet", getSyncName(cache).toString(), resource.getFullPath().toString()))); //$NON-NLS-1$ + // Assume there is no remote and the problem is a programming error + } + return null; + } + return RemoteFile.fromBytes(resource, remoteBytes, parentBytes); + } else { + return RemoteFolder.fromBytes(resource, remoteBytes); + } + } + } + + private String getSyncName(ResourceVariantByteStore cache) { + if (cache instanceof PersistantResourceVariantByteStore) { + return ((PersistantResourceVariantByteStore)cache).getSyncName().toString(); + } + return cache.getClass().getName(); + } + + + private byte[] getParentBytes(IResource resource) throws TeamException { + IContainer parent = resource.getParent(); + byte[] bytes = cache.getBytes(parent); + if (bytes == null ) { + bytes = getBaseBytes(parent, getTag(resource)); + } + return bytes; + } + + private byte[] getBaseBytes(IContainer parent, CVSTag tag) throws CVSException { + byte[] bytes; + // Look locally for the folder bytes + ICVSFolder local = CVSWorkspaceRoot.getCVSFolderFor(parent); + FolderSyncInfo info = local.getFolderSyncInfo(); + if (info == null) { + bytes = null; + } else { + // Use the folder sync from the workspace and the tag from the store + FolderSyncInfo newInfo = new FolderSyncInfo(info.getRepository(), info.getRoot(), tag, false); + bytes = newInfo.getBytes(); + } + return bytes; + } + + protected CVSTag getTag(IResource resource) { + return tag; + } + + /** + * Dispose of the underlying byte store + */ + public void dispose() { + getByteStore().dispose(); + } + + /* (non-Javadoc) + * @see org.eclipse.team.internal.core.subscribers.caches.ResourceVariantTree#setVariant(org.eclipse.core.resources.IResource, org.eclipse.team.core.synchronize.IResourceVariant) + */ + protected boolean setVariant(IResource local, IResourceVariant remote) throws TeamException { + boolean changed = super.setVariant(local, remote); + if (local.getType() == IResource.FILE && getByteStore().getBytes(local) != null && !parentHasSyncBytes(local)) { + // Log a warning if there is no sync bytes available for the resource's + // parent but there is valid sync bytes for the child + CVSProviderPlugin.log(new TeamException(Policy.bind("ResourceSynchronizer.missingParentBytesOnSet", getSyncName(getByteStore()), local.getFullPath().toString()))); //$NON-NLS-1$ + } + return changed; + } + + private boolean parentHasSyncBytes(IResource resource) throws TeamException { + if (resource.getType() == IResource.PROJECT) return true; + return getParentBytes(resource) != null; + } +} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSSynchronizationCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSSynchronizationCache.java deleted file mode 100644 index 32579df08..000000000 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CVSSynchronizationCache.java +++ /dev/null @@ -1,52 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2003 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.team.internal.ccvs.core.syncinfo; - -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.team.core.TeamException; -import org.eclipse.team.internal.core.subscribers.caches.PersistantResourceVariantByteStore; -import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; -import org.eclipse.team.internal.ccvs.core.Policy; - -/** - * Override <code>PersistantResourceVariantByteStore</code> to log an error - * if there are no parent bytes for a file. - */ -public class CVSSynchronizationCache extends PersistantResourceVariantByteStore { - - public CVSSynchronizationCache(QualifiedName name) { - super(name); - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.helpers.SynchronizationCache#setSyncBytes(org.eclipse.core.resources.IResource, byte[]) - */ - public boolean setBytes(IResource resource, byte[] bytes) throws TeamException { - boolean changed = super.setBytes(resource, bytes); - if (resource.getType() == IResource.FILE && getBytes(resource) != null && !parentHasSyncBytes(resource)) { - // Log a warning if there is no sync bytes available for the resource's - // parent but there is valid sync bytes for the child - CVSProviderPlugin.log(new TeamException(Policy.bind("ResourceSynchronizer.missingParentBytesOnSet", getSyncName().toString(), resource.getFullPath().toString()))); //$NON-NLS-1$ - } - return changed; - } - - /** - * Indicates whether the parent of the given local resource has sync bytes for its - * corresponding remote resource. The parent bytes of a remote resource are required - * (by CVS) to create a handle to the remote resource. - */ - protected boolean parentHasSyncBytes(IResource resource) throws TeamException { - if (resource.getType() == IResource.PROJECT) return true; - return (getBytes(resource.getParent()) != null); - } -} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/MultiTagResourceVariantTree.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/MultiTagResourceVariantTree.java new file mode 100644 index 000000000..742d35454 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/MultiTagResourceVariantTree.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.internal.ccvs.core.syncinfo; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.team.internal.ccvs.core.CVSTag; +import org.eclipse.team.internal.ccvs.core.util.Assert; +import org.eclipse.team.internal.core.subscribers.caches.ResourceVariantByteStore; + +/** + * A CVS resource variant tree that associates a different tag with each root project. + */ +public class MultiTagResourceVariantTree extends CVSResourceVariantTree { + + Map projects = new HashMap(); + + public MultiTagResourceVariantTree(ResourceVariantByteStore cache, boolean cacheFileContentsHint) { + super(cache, null, cacheFileContentsHint); + } + + public void addProject(IProject project, CVSTag tag) { + Assert.isNotNull(project); + Assert.isNotNull(tag); + projects.put(project, tag); + } + + /* (non-Javadoc) + * @see org.eclipse.team.internal.ccvs.core.syncinfo.CVSResourceVariantTree#getTag(org.eclipse.core.resources.IResource) + */ + protected CVSTag getTag(IResource resource) { + return (CVSTag)projects.get(resource.getProject()); + } +} diff --git a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SyncInfoCompareInput.java b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SyncInfoCompareInput.java index 3b95a0f5a..03b0ae06a 100644 --- a/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SyncInfoCompareInput.java +++ b/bundles/org.eclipse.team.ui/src/org/eclipse/team/ui/synchronize/viewers/SyncInfoCompareInput.java @@ -14,7 +14,6 @@ import java.lang.reflect.InvocationTargetException; import org.eclipse.compare.CompareConfiguration; import org.eclipse.compare.CompareEditorInput; -import org.eclipse.compare.CompareUI; import org.eclipse.compare.IContentChangeListener; import org.eclipse.compare.IContentChangeNotifier; import org.eclipse.compare.ITypedElement; |