diff options
author | Jean Michel-Lemieux | 2002-01-30 00:32:39 +0000 |
---|---|---|
committer | Jean Michel-Lemieux | 2002-01-30 00:32:39 +0000 |
commit | 1ada964186df89042d6ff68911eaff53791914e7 (patch) | |
tree | 614e76aed98213a6360ac76d11cfa93bcd4b9f3b /bundles/org.eclipse.team.cvs.core/src/org/eclipse | |
parent | c73fdca44c9cd8c3a3de7db899efb538096fcd3e (diff) | |
download | eclipse.platform.team-1ada964186df89042d6ff68911eaff53791914e7.tar.gz eclipse.platform.team-1ada964186df89042d6ff68911eaff53791914e7.tar.xz eclipse.platform.team-1ada964186df89042d6ff68911eaff53791914e7.zip |
Bug 8284, 7869, 7519: allow disconnectfrom CVS and refresh local to update the state information from local.
This release includes a complete change of the CVS sync mechanism. A fairly important change.
Diffstat (limited to 'bundles/org.eclipse.team.cvs.core/src/org/eclipse')
36 files changed, 1482 insertions, 1448 deletions
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProvider.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProvider.java index ed98b88c3..0fc89ef9f 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProvider.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProvider.java @@ -56,11 +56,12 @@ import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; import org.eclipse.team.internal.ccvs.core.client.Command.QuietOption; import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation; import org.eclipse.team.internal.ccvs.core.connection.CVSServerException; -import org.eclipse.team.internal.ccvs.core.resources.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; import org.eclipse.team.internal.ccvs.core.resources.RemoteFolder; import org.eclipse.team.internal.ccvs.core.resources.RemoteFolderTree; -import org.eclipse.team.internal.ccvs.core.resources.Synchronizer; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; +import org.eclipse.team.internal.ccvs.core.syncinfo.FileSystemSynchronizer; import org.eclipse.team.internal.ccvs.core.util.Util; public class CVSProvider implements ICVSProvider { @@ -373,17 +374,11 @@ public class CVSProvider implements ICVSProvider { /* * @see ICVSProvider#importAndCheckout(IProject, Properties, IProgressMonitor) */ - public void createModule( - IProject project, - Properties configuration, - IProgressMonitor monitor) - throws TeamException { - + public void createModule(IProject project, Properties configuration, IProgressMonitor monitor) throws TeamException { CVSRepositoryLocation location = buildRepository(configuration, false); boolean alreadyExists = isCached(location); addToCache(location); try { - // Get the import properties String message = configuration.getProperty("message"); //$NON-NLS-1$ if (message == null) @@ -421,7 +416,6 @@ public class CVSProvider implements ICVSProvider { // Set the folder sync info of the project to point to the remote module ICVSFolder folder = (ICVSFolder)Session.getManagedResource(project); folder.setFolderSyncInfo(new FolderSyncInfo(moduleName, location.getLocation(), null, false)); - Synchronizer.getInstance().save(monitor); // Register the project with Team // (unless the project already has the proper nature from the project meta-information) @@ -438,6 +432,8 @@ public class CVSProvider implements ICVSProvider { if ( ! alreadyExists) disposeRepository(location); throw e; + } finally { + CVSProviderPlugin.getSynchronizer().save(project.getLocation().toFile(), Policy.subMonitorFor(monitor, 5)); } // We succeeded so we should cache the password ... location.updateCache(); @@ -500,7 +496,6 @@ public class CVSProvider implements ICVSProvider { // Only set the info if there is none. info = new FolderSyncInfo(remotePath, location.getLocation(), tag, false); folder.setFolderSyncInfo(info); - Synchronizer.getInstance().save(monitor); } // Register the project with Team @@ -510,6 +505,8 @@ public class CVSProvider implements ICVSProvider { TeamPlugin.getManager().setProvider(project, CVSProviderPlugin.NATURE_ID, null, monitor); } catch (CoreException e) { throw wrapException(e); + } finally { + CVSProviderPlugin.getSynchronizer().save(project.getLocation().toFile(), Policy.subMonitorFor(monitor, 5)); } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java index 61ca984e8..3b3268f96 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java @@ -18,17 +18,23 @@ import org.eclipse.core.runtime.Plugin; import org.eclipse.team.core.ITeamProvider; import org.eclipse.team.core.TeamException; import org.eclipse.team.core.TeamPlugin; +import org.eclipse.team.core.sync.ISyncProvider; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.CVSProvider; import org.eclipse.team.internal.ccvs.core.Policy; import org.eclipse.team.internal.ccvs.core.client.Command.QuietOption; -import org.eclipse.team.internal.ccvs.core.resources.Synchronizer; +import org.eclipse.team.internal.ccvs.core.resources.ICVSSynchronizer; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.FileSystemSynchronizer; import org.eclipse.team.internal.ccvs.core.util.ProjectDescriptionManager; import org.eclipse.team.internal.ccvs.core.util.Util; public class CVSProviderPlugin extends Plugin { private static CVSProviderPlugin instance; + + private static ICVSSynchronizer synchronizer; + /** * Int used for the communications timeout on server connections (in seconds) */ @@ -145,7 +151,9 @@ public class CVSProviderPlugin extends Plugin { public void startup() throws CoreException { super.startup(); Policy.localize("org.eclipse.team.internal.ccvs.core.messages"); - Synchronizer.startup(); + + synchronizer = new FileSystemSynchronizer(); + CVSProvider.startup(); ProjectDescriptionManager.initializeChangeListener(); } @@ -157,6 +165,13 @@ public class CVSProviderPlugin extends Plugin { super.shutdown(); CVSProvider.shutdown(); } + + /** + * Returns the synchronizer reponsible for managing the CVS meta information. + */ + public static ICVSSynchronizer getSynchronizer() { + return synchronizer; + } /* * Add a resource change listener to the workspace in order to respond to diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java index 6b5f0d98f..445b3f85c 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java @@ -49,7 +49,6 @@ import org.eclipse.team.internal.ccvs.core.client.listeners.DiffListener; import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation; import org.eclipse.team.internal.ccvs.core.connection.CVSServerException; import org.eclipse.team.internal.ccvs.core.resources.CVSRemoteSyncElement; -import org.eclipse.team.internal.ccvs.core.resources.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.resources.ICVSFile; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; import org.eclipse.team.internal.ccvs.core.resources.ICVSResource; @@ -59,8 +58,10 @@ import org.eclipse.team.internal.ccvs.core.resources.LocalFolder; import org.eclipse.team.internal.ccvs.core.resources.LocalResource; 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.ResourceSyncInfo; -import org.eclipse.team.internal.ccvs.core.resources.Synchronizer; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +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.syncinfo.FileSystemSynchronizer; import org.eclipse.team.internal.ccvs.core.util.Assert; import org.eclipse.team.internal.ccvs.core.util.RemoteFolderTreeBuilder; @@ -123,14 +124,6 @@ public class CVSTeamProvider implements ITeamNature, ITeamProvider { * @see IProjectNature#deconfigure() */ public void deconfigure() throws CoreException { - // We want to clear the sync info for the project without deleting the CVS directories - // unmanage() does this - try { - managedProject.unmanage(); - } catch (CVSException e) { - throw new CoreException(new Status(IStatus.ERROR, CVSProviderPlugin.ID, 0, Policy.bind("CVSTeamProvider.deconfigureProblem", new Object[] {project.getName()}), e)); - } - project.refreshLocal(IResource.DEPTH_INFINITE, null); } /** @@ -550,11 +543,11 @@ public class CVSTeamProvider implements ITeamNature, ITeamProvider { }; for (int i = 0; i < resources.length; i++) { - getChild(resources[i]).accept(visitor); + IResource resource = resources[i]; + getChild(resource).accept(visitor); + CVSProviderPlugin.getSynchronizer().save(resource.getLocation().toFile(), progress); } - - Synchronizer.getInstance().save(progress); - + // Perform an update, ignoring any local file modifications update(resources, depth, null, true, progress); } @@ -880,7 +873,7 @@ public class CVSTeamProvider implements ITeamNature, ITeamProvider { } }; }); - Synchronizer.getInstance().save(new NullProgressMonitor()); + CVSProviderPlugin.getSynchronizer().save(project.getLocation().toFile(), new NullProgressMonitor()); return; } @@ -1034,26 +1027,6 @@ public class CVSTeamProvider implements ITeamNature, ITeamProvider { return new CVSStatus(IStatus.OK, "OK"); } - /** - * Call this method to refresh both the local CVS sync information (e.g. the files in the CVS subdirectories) and the - * contents of the files. This is useful when a command line client is invoked outside of the workbench and the user - * would like to continue working in the workbench with the modified state. - * - * @param resources to be refreshed deep - * @param progress a progress monitor to indicate the duration of the operation, or <code>null</code> if - * progress reporting is not required. - */ - public void refreshFromLocal(IResource[] resources, IProgressMonitor monitor) throws CVSException { - for (int i = 0; i < resources.length; i++) { - Synchronizer.getInstance().reload(new LocalFolder(resources[i].getLocation().toFile()),monitor); - try { - resources[i].refreshLocal(IResource.DEPTH_INFINITE, monitor); - } catch(CoreException e) { - throw new CVSException("Problems encountered refreshing from the local file system", e); - } - } - } - /* * @see ITeamProvider#refreshState(IResource[], int, IProgressMonitor) */ diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/AbstractStructureVisitor.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/AbstractStructureVisitor.java index efc727920..be7f466fe 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/AbstractStructureVisitor.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/AbstractStructureVisitor.java @@ -8,11 +8,12 @@ package org.eclipse.team.internal.ccvs.core.client; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.resources.CVSEntryLineTag; -import org.eclipse.team.internal.ccvs.core.resources.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.resources.ICVSFile; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; import org.eclipse.team.internal.ccvs.core.resources.ICVSResourceVisitor; -import org.eclipse.team.internal.ccvs.core.resources.ResourceSyncInfo; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +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.Assert; /** diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Add.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Add.java index 816442620..e5e085adb 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Add.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Add.java @@ -9,10 +9,11 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.client.Command.GlobalOption; import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; -import org.eclipse.team.internal.ccvs.core.resources.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; import org.eclipse.team.internal.ccvs.core.resources.ICVSResource; import org.eclipse.team.internal.ccvs.core.resources.ICVSResourceVisitor; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.util.Assert; public class Add extends Command { diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/CheckedInHandler.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/CheckedInHandler.java index 80cc34f80..a9bbc8a38 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/CheckedInHandler.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/CheckedInHandler.java @@ -9,7 +9,8 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.resources.ICVSFile; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; -import org.eclipse.team.internal.ccvs.core.resources.ResourceSyncInfo; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; /** * Handles a "Checked-in" response from the CVS server. diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java index 2ca78d26a..167b4a5d5 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java @@ -20,7 +20,7 @@ import org.eclipse.team.internal.ccvs.core.client.listeners.ICommandOutputListen import org.eclipse.team.internal.ccvs.core.resources.CVSFileNotFoundException; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; import org.eclipse.team.internal.ccvs.core.resources.ICVSResource; -import org.eclipse.team.internal.ccvs.core.resources.Synchronizer; +import org.eclipse.team.internal.ccvs.core.resources.LocalResource; /** * Abstract base class for the commands which implements the ICommand @@ -267,7 +267,26 @@ public abstract class Command { monitor = Policy.monitorFor(monitor); monitor.beginTask("", 100 * resources.length); for (int i = 0; i < resources.length; i++) { - Synchronizer.getInstance().reload(resources[i], Policy.subMonitorFor(monitor, 100)); + if(resources[i] instanceof LocalResource && resources[i].exists()) { + CVSProviderPlugin.getSynchronizer().reload(((LocalResource)resources[i]).getLocalFile(), Policy.subMonitorFor(monitor, 100)); + } + } + } finally { + monitor.done(); + } + } + + /** + * Reload the sync info for all arguments this command will be running on. + */ + private void saveSyncInfo(ICVSResource[] resources, IProgressMonitor monitor) throws CVSException { + try { + monitor = Policy.monitorFor(monitor); + monitor.beginTask("", 100 * resources.length); + for (int i = 0; i < resources.length; i++) { + if(resources[i] instanceof LocalResource) { + CVSProviderPlugin.getSynchronizer().save(((LocalResource)resources[i]).getLocalFile(), Policy.subMonitorFor(monitor, 100)); + } } } finally { monitor.done(); @@ -280,6 +299,7 @@ public abstract class Command { LocalOption[] localOptions, String[] arguments, ICommandOutputListener listener, IProgressMonitor monitor) throws CVSException { + ICVSResource[] resources = null; try { session.setNoLocalChanges(DO_NOT_CHANGE.isElementOf(globalOptions)); session.setModTime(null); @@ -290,7 +310,7 @@ public abstract class Command { // Ensure that the commands run with the latest contents of the CVS subdirectory sync files // and not the cached values. Allow 10% of work. - ICVSResource[] resources = computeWorkResources(session, arguments); + resources = computeWorkResources(session, arguments); reloadSyncInfo(resources, Policy.subMonitorFor(monitor, 10)); Policy.checkCanceled(monitor); @@ -319,15 +339,16 @@ public abstract class Command { // Processing responses contributes 70% of work. IStatus status = processResponses(session, listener, Policy.subMonitorFor(monitor, 70)); - // Finished adds last 10% of work. - commandFinished(session, globalOptions, localOptions, resources, monitor, + // Finished adds last 5% of work. + commandFinished(session, globalOptions, localOptions, resources, Policy.subMonitorFor(monitor, 5), status.getCode() != CVSException.SERVER_ERROR); - monitor.worked(10); + monitor.worked(5); return status; } finally { - // This will automatically persist any changes that were made to the - // sync info while running a command. - Synchronizer.getInstance().save(monitor); + // Give the synchronizer a chance to persist any pending changes. + if(resources!=null) { + saveSyncInfo(resources, Policy.subMonitorFor(monitor, 5)); + } monitor.done(); } } diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/DiffStructureVisitor.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/DiffStructureVisitor.java index 68ee3caca..ca5a49d1f 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/DiffStructureVisitor.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/DiffStructureVisitor.java @@ -7,7 +7,8 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.resources.ICVSFile; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; -import org.eclipse.team.internal.ccvs.core.resources.ResourceSyncInfo; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; /** * The diff command needs to send a file structure to the server that differs somewhat from the canonical diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/ResponseHandler.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/ResponseHandler.java index e6d8fb092..6eef70936 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/ResponseHandler.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/ResponseHandler.java @@ -8,8 +8,9 @@ package org.eclipse.team.internal.ccvs.core.client; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.resources.CVSEntryLineTag; -import org.eclipse.team.internal.ccvs.core.resources.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.util.Util; /** diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java index a070e6d90..cf030d99b 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java @@ -22,7 +22,8 @@ import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; import org.eclipse.team.internal.ccvs.core.resources.ICVSResource; import org.eclipse.team.internal.ccvs.core.resources.LocalFile; import org.eclipse.team.internal.ccvs.core.resources.LocalFolder; -import org.eclipse.team.internal.ccvs.core.resources.ResourceSyncInfo; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; public class Session { public static final String CURRENT_LOCAL_FOLDER = "."; diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/StaticHandler.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/StaticHandler.java index 90b54ccb3..f9a2cafa0 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/StaticHandler.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/StaticHandler.java @@ -7,8 +7,9 @@ package org.eclipse.team.internal.ccvs.core.client; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.internal.ccvs.core.CVSException; -import org.eclipse.team.internal.ccvs.core.resources.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.util.Assert; /** diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/StickyHandler.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/StickyHandler.java index 6672649bc..497fc207c 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/StickyHandler.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/StickyHandler.java @@ -8,8 +8,9 @@ package org.eclipse.team.internal.ccvs.core.client; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.resources.CVSEntryLineTag; -import org.eclipse.team.internal.ccvs.core.resources.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.util.Assert; /** diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/UpdatedHandler.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/UpdatedHandler.java index 003c9e3f2..9e63f0250 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/UpdatedHandler.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/UpdatedHandler.java @@ -12,7 +12,8 @@ import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.Policy; import org.eclipse.team.internal.ccvs.core.resources.ICVSFile; import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; -import org.eclipse.team.internal.ccvs.core.resources.ResourceSyncInfo; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; +import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; import org.eclipse.team.internal.ccvs.core.util.Assert; import org.eclipse.team.internal.ccvs.core.util.EntryFileDateFormat; diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSLocalSyncElement.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSLocalSyncElement.java index 7738a0d72..12e419820 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSLocalSyncElement.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSLocalSyncElement.java @@ -17,6 +17,7 @@ import org.eclipse.team.core.sync.IRemoteResource; import org.eclipse.team.core.sync.LocalSyncElement;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.CVSProvider;
+import org.eclipse.team.internal.ccvs.core.syncinfo.*;
public class CVSLocalSyncElement extends LocalSyncElement {
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java index bfcde8d75..813d1c537 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/CVSRemoteSyncElement.java @@ -7,6 +7,7 @@ package org.eclipse.team.internal.ccvs.core.resources; import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.team.ccvs.core.CVSProviderPlugin;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.team.ccvs.core.ICVSRemoteResource;
import org.eclipse.team.core.TeamException;
@@ -18,6 +19,7 @@ import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.CVSProvider;
import org.eclipse.team.internal.ccvs.core.Policy;
import org.eclipse.team.internal.ccvs.core.client.Session;
+import org.eclipse.team.internal.ccvs.core.syncinfo.*;
import org.eclipse.team.internal.ccvs.core.util.Assert;
public class CVSRemoteSyncElement extends RemoteSyncElement {
@@ -217,13 +219,13 @@ public class CVSRemoteSyncElement extends RemoteSyncElement { } else {
// We have conflicting deletions. Clear the sync info
local.setSyncInfo(null);
- Synchronizer.getInstance().save(Policy.monitorFor(monitor));
+ CVSProviderPlugin.getSynchronizer().save(((LocalResource)local).getLocalFile(), Policy.monitorFor(monitor));
return;
}
}
info = new ResourceSyncInfo(info.getName(), revision, info.getTimeStamp(), info.getKeywordMode(), local.getParent().getFolderSyncInfo().getTag(), info.getPermissions());
local.setSyncInfo(info);
- Synchronizer.getInstance().save(Policy.monitorFor(monitor));
+ CVSProviderPlugin.getSynchronizer().save(((LocalResource)local).getLocalFile(), Policy.monitorFor(monitor));
}
/*
@@ -243,11 +245,9 @@ public class CVSRemoteSyncElement extends RemoteSyncElement { } else if (outgoing) {
// For now, just unmanage the local resource so the remote change can be loaded with an update
Session.getManagedResource(getLocal()).unmanage();
- Synchronizer.getInstance().save(Policy.monitorFor(monitor));
} else {
// For now, just unmanage the local resource so the remote change can be loaded with an update
Session.getManagedResource(getLocal()).unmanage();
- Synchronizer.getInstance().save(Policy.monitorFor(monitor));
}
}
@@ -293,6 +293,6 @@ public class CVSRemoteSyncElement extends RemoteSyncElement { FolderSyncInfo remoteInfo = remote.getFolderSyncInfo();
FolderSyncInfo localInfo = local.getParent().getFolderSyncInfo();
local.setFolderSyncInfo(new FolderSyncInfo(remoteInfo.getRepository(), remoteInfo.getRoot(), localInfo.getTag(), localInfo.getIsStatic()));
- Synchronizer.getInstance().save(Policy.monitorFor(monitor));
- }
+ CVSProviderPlugin.getSynchronizer().save(((LocalResource)local).getLocalFile(), Policy.monitorFor(monitor));
+ }
}
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSFolder.java index 5da6bd914..f5dbd3ae5 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSFolder.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSFolder.java @@ -6,6 +6,7 @@ package org.eclipse.team.internal.ccvs.core.resources; */
import org.eclipse.team.internal.ccvs.core.CVSException;
+import org.eclipse.team.internal.ccvs.core.syncinfo.*;
/**
* The CVS analog of a directory. CVS folders have access to synchronization information
@@ -24,6 +25,7 @@ public interface ICVSFolder extends ICVSResource { * <li> does not exist() but is managed (deleted folder)
* <li> exist() and isManaged() (normal registered file)
* </ul>
+ * If the folder does not exist then a zero length array is returned.
*/
ICVSFolder[] getFolders() throws CVSException;
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSResource.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSResource.java index dcfb41b95..e3c54919b 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSResource.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSResource.java @@ -6,6 +6,7 @@ package org.eclipse.team.internal.ccvs.core.resources; */
import org.eclipse.team.internal.ccvs.core.CVSException;
+import org.eclipse.team.internal.ccvs.core.syncinfo.*;
/**
* The CVS analog of file system files and directories. These are handles to
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSSynchronizer.java new file mode 100644 index 000000000..603269455 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ICVSSynchronizer.java @@ -0,0 +1,112 @@ +package org.eclipse.team.internal.ccvs.core.resources; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ + +import java.io.File; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; + +/** + * A synchronizer is responsible for managing synchronization information for local + * CVS resources. + * + * @see ResourceSyncInfo + * @see FolderSyncInfo + */ +public interface ICVSSynchronizer { + + /** + * Associates the provided folder sync information with the given folder. The folder + * must exist on the file system. + * <p> + * The workbench and team plugins are notified that the state of this resources has + * changed.</p> + * + * @param file the file or folder for which to associate the sync info. + * @param info the folder sync to set. + * + * @throws CVSException if there was a problem adding sync info. + */ + public void setFolderSync(File folder, FolderSyncInfo info) throws CVSException; + + /** + * Answers the folder sync information associated with this folder or <code>null</code> + * if none is available. + * + * @param folder the folder for which to return folder sync info. + * @throws CVSException if there was a problem adding folder sync info. + */ + public FolderSyncInfo getFolderSync(File file) throws CVSException; + + /** + * Associates the provided sync information with the given file or folder. The resource + * may or may not exist on the file system however the parent folder must be a cvs + * folder. + * <p> + * The workbench and team plugins are notified that the state of this resources has + * changed.</p> + * + * @param file the file or folder for which to associate the sync info. + * @param info to set. The name in the resource info must match the file or folder name. + * + * @throws CVSException if there was a problem adding sync info. + */ + public void setResourceSync(File file, ResourceSyncInfo info) throws CVSException; + + /** + * Answers the sync information associated with this file of folder or <code>null</code> + * if none is available. A resource cannot have sync information if its parent folder + * does not exist. + * + * @param file the file or folder for which to return sync info. + * @throws CVSException if there was a problem adding sync info or broadcasting + * the changes. + */ + public ResourceSyncInfo getResourceSync(File file) throws CVSException; + + /** + * Removes the folder's and all children's folder sync information. This will essentially remove + * all CVS knowledge from these resources. + */ + public void deleteFolderSync(File file, IProgressMonitor monitor) throws CVSException; + + /** + * Removes the resource's sync information. + */ + public void deleteResourceSync(File file) throws CVSException; + + /** + * Allows the synchronizer to update the workspace with changes made by an 3rd + * party tool to the sync info. + */ + public void reload(File file, IProgressMonitor monitor) throws CVSException; + + /** + * Call to allow the synchronizer to save any pending or buffered changes and dispatch + * state change notifications. + */ + public void save(File file, IProgressMonitor monitor) throws CVSException; + + /** + * Answers an array with the sync information for immediate child resources of this folder. Note + * that the returned sync information may be for resources that no longer exist (e.g. in the + * case of a pending deletion). + * + * @param folder the folder for which to return the children resource sync infos. The folder + * must exist. + * + * @throws CVSException if an error occurs retrieving the sync info. + */ + public ResourceSyncInfo[] members(File folder) throws CVSException; + + /** + * XXX: Should be removed. Currently only used by tests and instead the tests should be + * created for the different types of concrete sync classes. + */ + public boolean isEmpty(); +}
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalFile.java index af91531fb..290c784b8 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalFile.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalFile.java @@ -5,7 +5,6 @@ package org.eclipse.team.internal.ccvs.core.resources; * All Rights Reserved.
*/
-import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -17,9 +16,10 @@ import java.text.ParseException; import java.util.Date;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.team.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.Policy;
-import org.eclipse.team.internal.ccvs.core.util.Assert;
+import org.eclipse.team.internal.ccvs.core.syncinfo.*;
import org.eclipse.team.internal.ccvs.core.util.EntryFileDateFormat;
import org.eclipse.team.internal.ccvs.core.util.Util;
@@ -264,7 +264,6 @@ public class LocalFile extends LocalResource implements ICVSFile { * @see ICVSResource#unmanage()
*/
public void unmanage() throws CVSException {
- Synchronizer.getInstance().deleteResourceSync(ioResource);
+ CVSProviderPlugin.getSynchronizer().deleteResourceSync(ioResource);
}
-}
-
+}
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalFolder.java index c5fafae28..f945b3cbe 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalFolder.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalFolder.java @@ -10,17 +10,12 @@ import java.io.FileFilter; import java.util.HashSet;
import java.util.Set;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.Status;
import org.eclipse.team.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.CVSException;
-import org.eclipse.team.internal.ccvs.core.CVSStatus;
import org.eclipse.team.internal.ccvs.core.Policy;
+import org.eclipse.team.internal.ccvs.core.syncinfo.*;
import org.eclipse.team.internal.ccvs.core.util.FileNameMatcher;
-import org.eclipse.team.internal.ccvs.core.util.SyncFileUtil;
/**
* Implements the ICVSFolder interface on top of an
@@ -40,10 +35,14 @@ public class LocalFolder extends LocalResource implements ICVSFolder { */
public ICVSFolder[] getFolders() throws CVSException {
+ if(!getLocalFile().exists()) {
+ return new ICVSFolder[0];
+ }
+
final Set folders = new HashSet();
final FileNameMatcher matcher = FileNameMatcher.getIgnoreMatcherFor(ioResource);
- ResourceSyncInfo[] syncDirs = Synchronizer.getInstance().members(ioResource);
+ ResourceSyncInfo[] syncDirs = CVSProviderPlugin.getSynchronizer().members(ioResource);
for (int i = 0; i < syncDirs.length; i++) {
if(syncDirs[i].isDirectory()) {
folders.add((new LocalFolder(new File(ioResource, syncDirs[i].getName()))));
@@ -67,10 +66,14 @@ public class LocalFolder extends LocalResource implements ICVSFolder { */
public ICVSFile[] getFiles() throws CVSException {
+ if(!getLocalFile().exists()) {
+ return new ICVSFile[0];
+ }
+
final Set files = new HashSet();
final FileNameMatcher matcher = FileNameMatcher.getIgnoreMatcherFor(ioResource);
- ResourceSyncInfo[] syncDirs = Synchronizer.getInstance().members(ioResource);
+ ResourceSyncInfo[] syncDirs = CVSProviderPlugin.getSynchronizer().members(ioResource);
for (int i = 0; i < syncDirs.length; i++) {
if(!syncDirs[i].isDirectory()) {
files.add((new LocalFile(new File(ioResource, syncDirs[i].getName()))));
@@ -218,14 +221,14 @@ public class LocalFolder extends LocalResource implements ICVSFolder { * @see ICVSFolder#getFolderInfo()
*/
public FolderSyncInfo getFolderSyncInfo() throws CVSException {
- return Synchronizer.getInstance().getFolderSync(ioResource);
+ return CVSProviderPlugin.getSynchronizer().getFolderSync(ioResource);
}
/*
* @see ICVSFolder#setFolderInfo(FolderSyncInfo)
*/
public void setFolderSyncInfo(FolderSyncInfo folderInfo) throws CVSException {
- Synchronizer.getInstance().setFolderSync(ioResource, folderInfo);
+ CVSProviderPlugin.getSynchronizer().setFolderSync(ioResource, folderInfo);
}
/*
@@ -233,9 +236,8 @@ public class LocalFolder extends LocalResource implements ICVSFolder { */
public boolean isCVSFolder() {
try {
- return Synchronizer.getInstance().getFolderSync(ioResource) != null;
+ return CVSProviderPlugin.getSynchronizer().getFolderSync(ioResource) != null;
} catch(CVSException e) {
- CVSProviderPlugin.log(new CVSStatus(IStatus.ERROR, Path.EMPTY, "CVS error getting folder sync info", e));
return false;
}
}
@@ -244,6 +246,6 @@ public class LocalFolder extends LocalResource implements ICVSFolder { * @see ICVSResource#unmanage()
*/
public void unmanage() throws CVSException {
- Synchronizer.getInstance().deleteFolderSync(ioResource, new NullProgressMonitor());
+ CVSProviderPlugin.getSynchronizer().deleteFolderSync(ioResource, new NullProgressMonitor());
}
}
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalResource.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalResource.java index 361e7f0b3..5a41bfeae 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalResource.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/LocalResource.java @@ -7,8 +7,9 @@ package org.eclipse.team.internal.ccvs.core.resources; import java.io.File;
-import org.eclipse.core.resources.IResource;
+import org.eclipse.team.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.CVSException;
+import org.eclipse.team.internal.ccvs.core.syncinfo.*;
import org.eclipse.team.internal.ccvs.core.util.FileNameMatcher;
import org.eclipse.team.internal.ccvs.core.util.FileUtil;
import org.eclipse.team.internal.ccvs.core.util.Util;
@@ -143,14 +144,14 @@ public abstract class LocalResource implements ICVSResource { * @see ICVSResource#getSyncInfo()
*/
public ResourceSyncInfo getSyncInfo() throws CVSException {
- return Synchronizer.getInstance().getResourceSync(ioResource);
+ return CVSProviderPlugin.getSynchronizer().getResourceSync(ioResource);
}
/*
* @see ICVSResource#setSyncInfo(ResourceSyncInfo)
*/
public void setSyncInfo(ResourceSyncInfo info) throws CVSException {
- Synchronizer.getInstance().setResourceSync(ioResource, info);
+ CVSProviderPlugin.getSynchronizer().setResourceSync(ioResource, info);
}
/*
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java index 129af60f0..2798e6269 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java @@ -31,6 +31,7 @@ import org.eclipse.team.internal.ccvs.core.client.Update; import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; import org.eclipse.team.internal.ccvs.core.client.listeners.LogListener; import org.eclipse.team.internal.ccvs.core.connection.CVSServerException; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; import org.eclipse.team.internal.ccvs.core.util.Assert; /** diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolder.java index 1f63a4851..7be17c5c9 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolder.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolder.java @@ -36,6 +36,7 @@ import org.eclipse.team.internal.ccvs.core.client.listeners.StatusListener; import org.eclipse.team.internal.ccvs.core.client.listeners.UpdateListener; import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation; import org.eclipse.team.internal.ccvs.core.connection.CVSServerException; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; /** * This class provides the implementation of ICVSRemoteFolder diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteResource.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteResource.java index 21fed0d4f..85192e071 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteResource.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteResource.java @@ -13,6 +13,7 @@ import org.eclipse.team.ccvs.core.ICVSRemoteResource; import org.eclipse.team.ccvs.core.ICVSRepositoryLocation; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.Policy; +import org.eclipse.team.internal.ccvs.core.syncinfo.*; import org.eclipse.team.internal.ccvs.core.util.Assert; import org.eclipse.team.internal.ccvs.core.util.NullOutputStream; diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/Synchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/Synchronizer.java deleted file mode 100644 index 28a7eff00..000000000 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/Synchronizer.java +++ /dev/null @@ -1,608 +0,0 @@ -package org.eclipse.team.internal.ccvs.core.resources;
-
-/*
- * (c) Copyright IBM Corp. 2000, 2001.
- * All Rights Reserved.
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-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.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.team.ccvs.core.CVSProviderPlugin;
-import org.eclipse.team.core.TeamPlugin;
-import org.eclipse.team.internal.ccvs.core.CVSException;
-import org.eclipse.team.internal.ccvs.core.Policy;
-import org.eclipse.team.internal.ccvs.core.util.Assert;
-import org.eclipse.team.internal.ccvs.core.util.ResourceDeltaVisitor;
-import org.eclipse.team.internal.ccvs.core.util.SyncFileUtil;
-
-/**
- * A singleton that provides clients access to CVS synchronization information
- * about local files and folder. In addition, when sync information is modified
- * via this class, the Team plugin is notified of a state change and the resource
- * is refreshed within the workbench.
- * <p>
- * All set and delete methods on the synchronizer do not persist the sync information
- * to disk, instead clients modifying the sync info must call <code>save()</code>
- * to persist the sync information.</p>
- * <p>
- * A client may set/get resource sync info for files that don't exist on the file
- * system yet. This is mainly to support having sync info for deleted files. However,
- * to set/get folder sync info the underlying folder in the file system must exist.</p>
- *
- * [Note: it may be interesting to implement a mechanism for invalidating cache items
- * based on a LRU - least recently used, algorithm. This could potentially save a lot
- * of memory for very large workspaces.]
- *
- * @see ResourceSyncInfo
- * @see FolderSyncInfo
- */
-public class Synchronizer {
-
- // the one and only instance.
- private static Synchronizer instance;
- private static SyncResourceDeletionListener deletedListener;
-
- // cache containing ResourceSyncInfo that are created from the entry file and permission file
- // {keys = Entry File files values = SyncFile}
- // {Syncfile is keys = file name values = ResourceSyncInfo}
- private Map entriesCache = new HashMap(10);
-
- // cache containing FolderSyncInfo that are created from the CVS subdirectory folder config
- // files
- // {keys = Folder values = FolderSyncInfo}
- private Map folderConfigCache = new HashMap(10);
-
- // used to remember entry files and folders that are modified in memory but have
- // not been saved.
- private Set invalidatedEntryFiles = new HashSet(10);
- private Set invalidatedFolderConfigs = new HashSet(10);
-
- // Fields for progress monitoring algorithm. Initially, give progress for every 4 resources, double
- // this value at halfway point, then reset halfway point to be half of remaining work. (this gives an infinite
- // series that converges at total work after an infinite number of resources).
- public static final int TOTAL_WORK = 250;
- private int halfWay = TOTAL_WORK / 2;
- private int currentIncrement = 4;
- private int nextProgress = currentIncrement;
- private int worked = 0;
-
- /**
- * Data structured used in the cache tables to save information about file contents that
- * are read from disk.
- */
- private class SyncFile {
- long timestamp = 0;
- Map config = new HashMap(10);
- }
-
- /**
- * When a container resource in the workbench is deleted the Synchronizer must clear the cache so that
- * stale sync infos are removed.
- */
- public class SyncResourceDeletionListener extends ResourceDeltaVisitor {
- protected void handleAdded(IProject project, IResource resource) {
- }
- protected void handleRemoved(IProject project, IResource resource) {
- try {
- if(resource.getType()!=IResource.FILE && !resource.getName().equals("CVS")) {
- String location = new Path(project.getWorkspace().getRoot().getLocation().toString()).append(resource.getFullPath()).toString();
- Synchronizer.getInstance().deleteFolderSync(new File(location), new NullProgressMonitor());
- }
- } catch(CVSException e) {
- CVSProviderPlugin.log(new Status(IStatus.WARNING, CVSProviderPlugin.ID, 0, "Could not delete CVS folder sync info", null));
- }
- }
- protected void handleChanged(IProject project, IResource resource) {
- }
- }
-
- /**
- * Debug method that displays the contents of the cache.
- */
- public void dump() {
- System.out.println("Synchronizer:");
- System.out.println("\tEntries");
- for (Iterator it = entriesCache.keySet().iterator(); it.hasNext();) {
- File entriesFile = (File)it.next();
- SyncFile contents = (SyncFile)entriesCache.get(entriesFile);
- System.out.println(entriesFile.getAbsolutePath() + " (" + contents.config.size() +")");
- for (Iterator it2 = contents.config.keySet().iterator(); it2.hasNext();) {
- System.out.println(((String)it2.next()));
- }
- }
-
- System.out.println("\tFolders");
- for (Iterator it = folderConfigCache.keySet().iterator(); it.hasNext();) {
- File folder = (File)it.next();
- System.out.println(folder.getAbsolutePath());
- }
- }
-
- /**
- * Singleton constructor
- */
- private Synchronizer() {
- }
-
- /**
- * Answer the singleton instance of the Synchronizer.
- */
- public static Synchronizer getInstance() {
- return instance;
- }
-
- /**
- * On startup, initialize the synchronizer instance
- */
- public static void startup() {
- instance = new Synchronizer();
- deletedListener = instance.new SyncResourceDeletionListener();
- deletedListener.register();
- }
-
- /**
- * Associates the provided sync information with the given file or folder. The resource
- * may or may not exist on the file system however the parent folder must have a CVS
- * subdirectory.
- * <p>
- * The workbench and team plugins are notified that the state of this resources has
- * changed.</p>
- *
- * @param file the file or folder for which to associate the sync info.
- * @param info to set. The name in the resource info must match the file or folder name.
- *
- * @throws CVSException if there was a problem adding sync info or broadcasting
- * the changes. If the parent folder does not have a CVS subdirectory.
- */
- public synchronized void setResourceSync(File file, ResourceSyncInfo info) throws CVSException {
-
- Assert.isNotNull(file);
- Assert.isNotNull(info);
- Assert.isTrue(info.getName().equals(file.getName()));
-
- File parentCVSDir = SyncFileUtil.getCVSSubdirectory(file.getParentFile());
- File entriesFile = new File(parentCVSDir, SyncFileUtil.ENTRIES);
-
- if(!parentCVSDir.exists()) {
- throw new CVSException("Parent folder does not have a CVS directory");
- }
-
- SyncFile entriesSync = (SyncFile)entriesCache.get(entriesFile);
- if(entriesSync==null) {
- entriesSync = new SyncFile();
- entriesCache.put(entriesFile, entriesSync);
- }
- entriesSync.config.put(info.getName(), info);
- invalidatedEntryFiles.add(entriesFile);
- }
-
- /**
- * Answers the sync information associated with this file of folder or <code>null</code>
- * if none is available. A resource cannot have sync information if its parent folder
- * does not exist.
- *
- * @param file the file or folder for which to return sync info.
- * @throws CVSException if there was a problem adding sync info or broadcasting
- * the changes.
- */
- public synchronized ResourceSyncInfo getResourceSync(File file) throws CVSException {
- return getResourceSync(file, false);
- }
-
- /**
- * Remove the sync information associated with this file.
- * <p>
- * The workbench and team plugins are notified that the state of this resources has
- * changed.</p>
- *
- * @param file the file or folder for which to delete its resource sync info.
- *
- * @throws CVSException if there was a problem removing sync info or broadcasting
- * the changes.
- */
- public synchronized void deleteResourceSync(File file) throws CVSException {
- File entriesFile = new File(SyncFileUtil.getCVSSubdirectory(file.getParentFile()), SyncFileUtil.ENTRIES);
- SyncFile entriesSync = (SyncFile)entriesCache.get(entriesFile);
- if(entriesSync!=null) {
- entriesSync.config.remove(file.getName());
- invalidatedEntryFiles.add(entriesFile);
- broadcastSyncChange(new File[] {file}, true);
- }
- }
-
- /**
- * Answers the folder sync information associated with this folder or <code>null</code>
- * if none is available.
- *
- * @param folder the folder for which to return folder sync info.
- * @throws CVSException if there was a problem adding folder sync info or broadcasting
- * the changes. If the folder does not exist on the file system.
- */
- public synchronized FolderSyncInfo getFolderSync(File folder) throws CVSException {
- return getFolderSync(folder, false);
- }
-
- /**
- * Associates the provided folder sync information with the given folder. The folder
- * must exist on the file system.
- * <p>
- * The workbench and team plugins are notified that the state of this resources has
- * changed.</p>
- *
- * @param file the file or folder for which to associate the sync info.
- * @param info to set. The name in the resource info must match the file or folder name.
- *
- * @throws CVSException if there was a problem adding sync info or broadcasting
- * the changes. If the folder does not exist on the file system.
- */
- public synchronized void setFolderSync(File folder, FolderSyncInfo info) throws CVSException {
-
- Assert.isNotNull(info);
-
- if(!folder.exists()) {
- throw new CVSException("Folder must exist to set sync info");
- }
-
- File cvsDirectory = SyncFileUtil.getCVSSubdirectory(folder);
- if(!cvsDirectory.exists()) {
- cvsDirectory.mkdir();
- }
-
- // if parent has the sync folder (e.g. CVS) then ensure that the directory
- // entry for this folder is added.
- if(getFolderSync(folder.getParentFile())!=null) {
- ResourceSyncInfo resourceInfo = new ResourceSyncInfo(folder.getName());
- setResourceSync(folder, resourceInfo);
- }
-
- // there can only be one sync entry for folders, create a new one
- folderConfigCache.remove(folder);
- SyncFile folderSync = new SyncFile();
- folderSync.config.put(folder.getName(), info);
- folderConfigCache.put(folder, folderSync);
- invalidatedFolderConfigs.add(folder);
- }
-
- /**
- * Remove the folder sync information associated with this folder and all its
- * children. If a parent folder does not have folder sync (e.g. is not managed
- * by CVS) then all children must also not have sync information.
- * <p>
- * The workbench and team plugins are notified that the state of this resources has
- * changed.</p>
- *
- * @param folder the root folder at which to start deleting.
- * @param monitor the progress monitor, cannot be <code>null</code>.
- *
- * @throws CVSException if there was a problem removing sync info or broadcasting
- * the changes.
- */
- public synchronized void deleteFolderSync(File folder, IProgressMonitor monitor) throws CVSException {
- ResourceSyncInfo[] children = members(folder);
-
- for (int i = 0; i < children.length; i++) {
- if(children[i].isDirectory()) {
- deleteFolderSync(new File(folder, children[i].getName()), monitor);
- }
- }
-
- deleteFolderAndChildEntries(folder, true);
- }
-
- /**
- * The set and delete methods on the synchronizer do not persist the sync information
- * to disk, instead clients modifying the sync info must call this method to
- * persist the sync information.
- *
- * @param monitor the progress monitor, cannot be <code>null</code>.
- *
- * @throws CVSException if there was a problem persisting the changes to disk.
- */
- public synchronized void save(IProgressMonitor monitor) throws CVSException {
- List filesToUpdate = new ArrayList();
- for (Iterator it = invalidatedEntryFiles.iterator(); it.hasNext();) {
- File entryFile = (File) it.next();
- SyncFile info = (SyncFile)entriesCache.get(entryFile);
-
- // entry file may of been deleted from cache by a client calling
- // deleteFolderSync (e.g. pruning on update).
- if(info!=null) {
-
- // collect all sync infos for this entries file
- List syncInfos = new ArrayList();
- for (Iterator it2 = info.config.values().iterator(); it2.hasNext();) {
- ResourceSyncInfo element = (ResourceSyncInfo) it2.next();
- syncInfos.add(element);
- filesToUpdate.add(new File(entryFile.getParentFile().getParentFile(), element.getName()));
- }
-
- if(!entryFile.exists()) {
- try {
- entryFile.getParentFile().mkdirs();
- entryFile.createNewFile();
- } catch(IOException e) {
- throw new CVSException("Error creating " + entryFile.getAbsolutePath(), e);
- }
- }
-
- SyncFileUtil.writeEntriesFile(entryFile, (ResourceSyncInfo[]) syncInfos.toArray(new ResourceSyncInfo[syncInfos.size()]));
-
- // ensure that the external sync files are kept in sync with the workbench
- File[] entrySyncFiles = SyncFileUtil.getEntrySyncFiles(entryFile.getParentFile().getParentFile());
- broadcastSyncChange(entrySyncFiles, false);
- }
- }
-
- for (Iterator it = invalidatedFolderConfigs.iterator(); it.hasNext();) {
- File folder = (File) it.next();
- SyncFile info = (SyncFile)folderConfigCache.get(folder);
-
- // folder config may of been deleted from cache by a client calling
- // deleteFolderSync (e.g. pruning on update).
- if(info!=null) {
- SyncFileUtil.writeFolderConfig(folder, (FolderSyncInfo)info.config.get(folder.getName()));
- File rootFile = new File(SyncFileUtil.getCVSSubdirectory(folder), SyncFileUtil.ROOT);
- info.timestamp = rootFile.lastModified();
-
- // ensure that the external sync files are kept in sync with the workbench.
- File[] folderSyncFiles = SyncFileUtil.getFolderSyncFiles(folder);
- broadcastSyncChange(folderSyncFiles, false);
- }
- }
-
- // broadcast state changes for non-metadata files that have changed
- if(!filesToUpdate.isEmpty()) {
- broadcastSyncChange((File[]) filesToUpdate.toArray(new File[filesToUpdate.size()]), true);
- }
-
- // clear invalidated lists
- invalidatedEntryFiles.clear();
- invalidatedFolderConfigs.clear();
- }
-
- /**
- * Answers the sync information for child resources of this folder. Note that the
- * returned sync information may be for resources that no longer exist (e.g. in the
- * case of a pending deletion.)
- *
- * @param folder the folder for which to return the children resource sync infos.
- */
- public ResourceSyncInfo[] members(File folder) throws CVSException {
- File entriesFile = new File(SyncFileUtil.getCVSSubdirectory(folder), SyncFileUtil.ENTRIES);
- SyncFile entriesSync = (SyncFile)entriesCache.get(entriesFile);
-
- if(entriesSync==null) {
- return new ResourceSyncInfo[0];
- }
- Collection entries = entriesSync.config.values();
- return (ResourceSyncInfo[])entries.toArray(new ResourceSyncInfo[entries.size()]);
- }
-
- /**
- * Reload the sync information from disk for this folder and all its children depth first.
- *
- * @param folder the root folder at which to start reloading.
- * @param monitor the progress monitor, cannot be <code>null</code>.
- */
- public void reload(ICVSResource resource, IProgressMonitor monitor) throws CVSException {
- try {
- monitor = Policy.monitorFor(monitor);
- monitor.beginTask("", TOTAL_WORK);
- doReload(resource, monitor);
- } finally {
- monitor.done();
- }
- }
-
- /**
- * Clear the entire synchronizer cache. This will force a reload of sync information from
- * disk on subsequent get calls. There must not be any invalidated sync infos.
- */
- public void clear() {
- Assert.isTrue(invalidatedEntryFiles.isEmpty() && invalidatedFolderConfigs.isEmpty());
- entriesCache.clear();
- folderConfigCache.clear();
- }
-
- /**
- * Answers if the cache is empty and there are no pending saves.
- */
- public boolean isEmpty() {
- return entriesCache.isEmpty() && folderConfigCache.isEmpty();
- }
-
- /**
- * Internal helping for returning the folder sync info. If reload is <code>true</code>
- * then load entries from disk.
- *
- * @param folder the folder for which to retrieve folder sync info.
- * @param reload if <code>true</code> then reload config from disk, if <code>false</code>
- * config is taken from cache and reloaded only if it is not cached.
- */
- protected FolderSyncInfo getFolderSync(File folder, boolean reload) throws CVSException {
- SyncFile folderSync = (SyncFile)folderConfigCache.get(folder);
- if(folderSync==null || reload) {
-
- if(!folder.exists()) {
- return null;
- }
-
- folderSync = new SyncFile();
- FolderSyncInfo info = SyncFileUtil.readFolderConfig(folder);
-
- // no CVS sub-directory
- if(info==null) {
- return null;
- }
- folderSync.config.put(folder.getName(), info);
- folderConfigCache.put(folder, folderSync);
- }
- return (FolderSyncInfo)folderSync.config.get(folder.getName());
- }
-
- /**
- * Internal helping for returning the folder sync info. If reload is <code>true</code>
- * then load entries from disk.
- *
- * @param folder the folder for which to retrieve folder sync info.
- * @param reload if <code>true</code> then reload config from disk, if <code>false</code>
- * config is taken from cache and reloaded only if it is not cached.
- */
- protected ResourceSyncInfo getResourceSync(File file, boolean reload) throws CVSException {
- File entriesFile = new File(SyncFileUtil.getCVSSubdirectory(file.getParentFile()), SyncFileUtil.ENTRIES);
- SyncFile entriesSync = (SyncFile)entriesCache.get(entriesFile);
-
- // read entries file
- if(entriesSync==null || reload) {
- entriesSync = new SyncFile();
- ResourceSyncInfo infos[] = SyncFileUtil.readEntriesFile(file.getParentFile());
- // entries file does not exist
- if(infos==null) {
- entriesCache.remove(entriesFile);
- return null;
- }
- for (int i = 0; i < infos.length; i++) {
- entriesSync.config.put(infos[i].getName(), infos[i]);
- }
- entriesCache.put(entriesFile, entriesSync);
- }
- return (ResourceSyncInfo)entriesSync.config.get(file.getName());
- }
-
- /**
- * Notifies the worbench and the team plugin that changes to a resource have
- * occured. This allows components interested in the CVS state of a resource to
- * update when state changes, and also to keep resources in sync with the
- * workspace by refreshing the contents.
- *
- * @param file a file that has its CVS state changed. If the file does not exist
- * then the parent if notified instead.
- */
- protected void broadcastSyncChange(File[] files, boolean notifyOfStateChange) throws CVSException {
- List resourcesToUpdate = new ArrayList();
- int depth = IResource.DEPTH_ZERO;
-
- for(int i=0; i < files.length; i++) {
- File file = files[i];
- if(!file.exists()) {
- file = file.getParentFile();
- depth = IResource.DEPTH_ONE;
- }
-
- if(file.equals(ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile()) || !file.exists()) {
- return;
- }
-
- IResource resource;
- if(file.isDirectory()) {
- resource = ResourcesPlugin.getWorkspace().getRoot().getContainerForLocation(new Path(file.getAbsolutePath()));
- } else {
- resource = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(file.getAbsolutePath()));
- }
-
- if(resource!=null) {
- try {
- resourcesToUpdate.add(resource);
- resource.refreshLocal(depth, null);
- } catch(CoreException e) {
- // throw new CVSException("Error refreshing file from local contents " + file.getAbsolutePath(), e);
- }
- }
- }
- if(!resourcesToUpdate.isEmpty() && notifyOfStateChange) {
- TeamPlugin.getManager().broadcastResourceStateChanges((IResource[]) resourcesToUpdate.toArray(new IResource[resourcesToUpdate.size()]));
- }
- }
-
- /**
- * Deletes a folder and all its children's sync information from the cache.
- * <p>
- * The workbench and team plugins are notified that the state of this resources has
- * changed.</p>
- *
- * @param folder the root folder at which to start deleting sync information.
- */
- protected void deleteFolderAndChildEntries(File folder, boolean deleteResourceSync) throws CVSException {
-
- // remove resource sync entries file from the cache
- File entriesFile = new File(SyncFileUtil.getCVSSubdirectory(folder), SyncFileUtil.ENTRIES);
- entriesCache.remove(entriesFile);
-
- // remove from parent
- if(deleteResourceSync) {
- deleteResourceSync(folder);
- }
-
- // remove folder sync
- folderConfigCache.remove(folder);
-
- // notify of state change to this folder
- broadcastSyncChange(new File[] {folder}, true);
- }
-
- /**
- * Perform the reload.
- */
- private void doReload(ICVSResource resource, IProgressMonitor monitor) throws CVSException {
- if (resource instanceof LocalFolder) {
- LocalFolder fsFolder = (LocalFolder) resource;
- File file = fsFolder.getLocalFile();
-
- String message = Policy.bind("Synchronizer.reload", fsFolder.getName());
- monitor.subTask(message);
-
- ICVSFolder[] folders = fsFolder.getFolders();
- for (int i = 0; i < folders.length; i++) {
- ICVSFolder iCVSFolder = folders[i];
- reload(iCVSFolder, monitor);
- }
-
- FolderSyncInfo info = getFolderSync(file, true);
-
- // info will be null if the CVS subdirectory or folder does not exist, then we can safely
- // clear this folder from the cache. Otherwise, reload the entries file for this folder as
- // well.
- if(info==null) {
- deleteFolderAndChildEntries(file, false);
- } else {
- getResourceSync(new File(file, "dummy"), true);
- }
-
- // Update monitor work amount
- if (--nextProgress <= 0) {
- monitor.worked(1);
- worked++;
- if (worked >= halfWay) {
- //we have passed the current halfway point, so double the
- //increment and reset the halfway point.
- currentIncrement *= 2;
- halfWay += (TOTAL_WORK - halfWay) / 2;
- }
- //reset the progress counter to another full increment
- nextProgress = currentIncrement;
- }
- }
- if(resource instanceof LocalFile) {
- // force a reload of entries file of parent
- getResourceSync(((LocalFile)resource).getLocalFile(), true);
- }
- }
-}
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CacheData.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CacheData.java new file mode 100644 index 000000000..368a94f45 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/CacheData.java @@ -0,0 +1,44 @@ +package org.eclipse.team.internal.ccvs.core.syncinfo; + +import java.util.Calendar; +import java.util.Date; + +import org.eclipse.team.internal.ccvs.core.util.*; + +public class CacheData { + private Object data; + private Object id; + private Date expirationDate; + + public CacheData(Object id, Object data, int minutesToLive) { + this.id = id; + this.data = data; + this.expirationDate = null; // if not set then default is to live forever + if(minutesToLive>0) { + expirationDate = new Date(); + Calendar currentDate = Calendar.getInstance(); + currentDate.add(Calendar.MINUTE, minutesToLive); + expirationDate = currentDate.getTime(); + } + } + + public CacheData(Object id, Object data) { + this(id, data, 0); + } + + public boolean isExpired() { + if(expirationDate==null) { + return false; + } else { + return expirationDate.before(new Date()); + } + } + + public Object getId() { + return id; + } + + public Object getData() { + return data; + } +} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/FileSystemSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/FileSystemSynchronizer.java new file mode 100644 index 000000000..51ab65ea3 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/FileSystemSynchronizer.java @@ -0,0 +1,402 @@ +package org.eclipse.team.internal.ccvs.core.syncinfo; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ + +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.team.core.TeamPlugin; +import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.resources.*; +import org.eclipse.team.internal.ccvs.core.util.Assert; +import org.eclipse.team.internal.ccvs.core.util.FileUtil; +import org.eclipse.team.internal.ccvs.core.util.ResourceDeltaVisitor; +import org.eclipse.team.internal.ccvs.core.util.SyncFileUtil; + +/** + * The FileSystemSynchronizer stores sync information to be compatible with CVS command line + * clients. It is also responsible for synchronizing the workbench when changes are made to CVS + * metafiles (CVS/Entries, CVS/Root..) from outside of the workbench by 3rd party tools. + * + * @see ICVSSynchronizer + */ +public class FileSystemSynchronizer implements ICVSSynchronizer { + + // caches for resource and folder sync. These are required to provide timely access to + // sync information that may be shown in the UI. + private ICache resourceSyncCache; + private ICache folderSyncCache; + + // a specialized resource listener required to interpret metafile changes made to CVS managed + // resources. + private SyncResourceChangeListener resourceListener; + + // time in minutes that a cached sync object should remain in the cache. A time of 0 indicates + // that the cache object will never expire. + private final static int CACHE_EXPIRATION_MINUTES = 0; + + /** + * Initialize the caches and register as a resource listener. + */ + public FileSystemSynchronizer() { + resourceSyncCache = new SimpleCache(); + resourceSyncCache.registerLoader(new ResourceSyncCacheLoader()); + + folderSyncCache = new SimpleCache(); + folderSyncCache.registerLoader(new FolderSyncCacheLoader()); + + resourceListener = new SyncResourceChangeListener(); + resourceListener.register(); + } + + /** + * For every get request from the cache, load the entire entries and permissions file. + */ + private class ResourceSyncCacheLoader implements ICacheLoader { + /* + * @see ICacheLoader#load(Object, ICache) + */ + public CacheData load(Object id, ICache cache) { + CacheData idInfo = null; + try { + File file = (File)id; + File parent = file.getParentFile(); + Assert.isTrue(parent.exists()); + + ResourceSyncInfo infos[] = SyncFileUtil.readEntriesFile(parent); + // if null then, entries file does not exist + if(infos!=null) { + for (int i = 0; i < infos.length; i++) { + ResourceSyncInfo info = infos[i]; + CacheData cacheInfo = new CacheData(new File(parent, info.getName()), info, CACHE_EXPIRATION_MINUTES); + if(file.getName().equals(info.getName())) { + idInfo = cacheInfo; + } else { + cache.put(cacheInfo); + } + } + } + } catch(CVSException e) { + TeamPlugin.log(IStatus.ERROR, "Error loading from CVS/Entries file", e); + return null; + } + return idInfo; + } + } + + /** + * For every get request from the cache that fails, load the files that contain the folder sync info. + */ + private class FolderSyncCacheLoader implements ICacheLoader { + /* + * @see ICacheLoader#load(Object, ICache) + */ + public CacheData load(Object id, ICache cache) { + try { + File folder = (File)id; + Assert.isTrue(folder.exists()); + FolderSyncInfo info = SyncFileUtil.readFolderConfig(folder); + + // no CVS sub-directory + if(info==null) { + return null; + } else { + return new CacheData(folder, info, CACHE_EXPIRATION_MINUTES); + } + } catch(CVSException e) { + TeamPlugin.log(IStatus.ERROR, "Error loading from CVS/Entries file", e); + return null; + } + } + } + + /** + * Handle changes made to meta files. + * 1. + */ + private class SyncResourceChangeListener extends ResourceDeltaVisitor { + private Set delta = new HashSet(); + + protected void handleAdded(IResource[] resources) { + handleDefault(resources); + } + + protected void handleRemoved(IResource[] resources) { + for (int i = 0; i < resources.length; i++) { + IResource resource = resources[i]; + File file = resource.getLocation().toFile(); + // if a resource is deleted, then clear the cache, there is not need for a delta. + if(!SyncFileUtil.isMetaFile(file)) { + clearCache(file, IResource.DEPTH_INFINITE); + } else { + if(resource.getName().equals("CVS")) { + handleMetaChange(file, resource); + } + } + } + } + + protected void handleChanged(IResource[] resources) { + handleDefault(resources); + } + + protected void finished() { + TeamPlugin.getManager().broadcastResourceStateChanges((IResource[]) delta.toArray(new IResource[delta.size()])); + delta.clear(); + } + + /** + * If a meta file has changed the cache will be out-of-date. It will be cleared and subsequent access + * will force a reload of the sync information when needed by a client. + */ + private void handleMetaChange(File cvsdir, IResource resource) { + File parent = cvsdir.getParentFile(); + clearCache(parent, IResource.DEPTH_ONE); + + // generate deltas for children of the parent because their state may of changed. + // it is safe to get the parent two up from the metafile because we have already + // confirmed that this is a meta directory. + if(resource.exists()) { + IContainer resourceParent = resource.getParent(); + delta.add(resourceParent); + try { + IResource[] children = resourceParent.members(); + for (int i = 0; i < children.length; i++) { + delta.add(children[i]); + } + } catch(CoreException e) { + // XXX what can you do in a resource listener when an exception occurs??? + } + } + } + + /** + * Canonical handling of a resource change + */ + private void handleDefault(IResource[] resources) { + for (int i = 0; i < resources.length; i++) { + File file = resources[i].getLocation().toFile(); + if(SyncFileUtil.isMetaFile(file)) { + handleMetaChange(file.getParentFile(), resources[i].getParent()); + // add all parents children to delta + } else { + if(!file.getName().equals("CVS")) { + delta.add(resources[i]); + } + } + } + } + } + + /* + * @see ICVSSynchronizer#getFolderSync(File) + */ + public FolderSyncInfo getFolderSync(File file) throws CVSException { + if(file.exists() && file.isDirectory()) { + LocalFolder folder = new LocalFolder(file); + if(SyncFileUtil.getCVSSubdirectory(file).exists()) { + CacheData data = (CacheData)folderSyncCache.get(file, null); + if(data!=null) { + return (FolderSyncInfo)data.getData(); + } + } + } + return null; + } + + /* + * @see ICVSSynchronizer#getResourceSync(File) + */ + public ResourceSyncInfo getResourceSync(File file) throws CVSException { + LocalFolder parent = new LocalFolder(file.getParentFile()); + if(parent.exists() && parent.isCVSFolder()) { + CacheData data = (CacheData)resourceSyncCache.get(file, null); + if(data!=null) { + return (ResourceSyncInfo)data.getData(); + } + } + return null; + } + + /* + * @see ICVSSynchronizer#setFolderSync(File, FolderSyncInfo) + */ + public void setFolderSync(File file, FolderSyncInfo info) throws CVSException { + Assert.isNotNull(info); + Assert.isTrue(file.exists()); + + SyncFileUtil.writeFolderConfig(file, info); + folderSyncCache.put(new CacheData(file, info, CACHE_EXPIRATION_MINUTES)); + + // the server won't add directories as sync info, therefore it must be done when + // a directory is shared with the repository. + setResourceSync(file, new ResourceSyncInfo(file.getName())); + + } + + /* + * @see ICVSSynchronizer#setResourceSync(File, ResourceSyncInfo) + */ + public void setResourceSync(File file, ResourceSyncInfo info) throws CVSException { + Assert.isNotNull(info); + Assert.isTrue(file.getParentFile().exists()); + Assert.isTrue(file.getName().equals(info.getName())); + + try { + LocalFolder parent = new LocalFolder(file.getParentFile()); + if(parent.exists() && parent.isCVSFolder()) { + SyncFileUtil.writeResourceSync(file, info); + } + } catch(CVSException e) { + // XXX Bad eating of exception + } + resourceSyncCache.put(new CacheData(file, info, CACHE_EXPIRATION_MINUTES)); + } + + /* + * @see ICVSSynchronizer#deleteFolderSync(File, IProgressMonitor) + */ + public void deleteFolderSync(File file, IProgressMonitor monitor) throws CVSException { + destroySyncDeep(file, monitor); + } + + /* + * @see ICVSSynchronizer#deleteResourceSync(File) + */ + public void deleteResourceSync(File file) { + try { + SyncFileUtil.deleteSync(file); + } catch(CVSException e) { + // XXX Bad eating of exception + } + resourceSyncCache.remove(file); + } + + /* + * If the file no longer exists, then clear the cache, or else, refresh from local and allow the + * resource change listener to adapt to changes. + * + * @see ICVSSynchronizer#reload(File, IProgressMonitor) + */ + public void reload(File file, IProgressMonitor monitor) throws CVSException { + + clearCache(file, IResource.DEPTH_INFINITE); + + if(!file.exists()) { + // a non-existant file implies that there is no longer any meta information + // on disk, we can safely clear the cache. + // we can safely reload the parent if it exists. + file = file.getParentFile(); + if(!file.exists()) { + return; + } + } + + // the following is to refresh the workbench with the local file changes. + if(file.equals(ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile())) { + return; + } + + IResource resource; + if(file.isDirectory()) { + resource = ResourcesPlugin.getWorkspace().getRoot().getContainerForLocation(new Path(file.getAbsolutePath())); + } else { + // reload a container always, or else sync info changes won't be loaded! + resource = ResourcesPlugin.getWorkspace().getRoot().getContainerForLocation(new Path(file.getParentFile().getAbsolutePath())); + } + try { + if(resource!=null) { + resource.refreshLocal(IResource.DEPTH_INFINITE, monitor); + } + } catch(CoreException e) { + throw new CVSException(IStatus.ERROR, 0, "Error reloading sync information", e); + } + } + + /* + * Simply reload to absorb changes made to the underlying file system. + * + * @see ICVSSynchronizer#save(File, IProgressMonitor) + */ + public void save(File file, IProgressMonitor monitor) throws CVSException { + reload(file, monitor); + } + + /* + * Answers if the caches are empty. + * + * @see ICVSSynchronizer#isEmpty() + */ + public boolean isEmpty() { + return resourceSyncCache.isEmpty() && folderSyncCache.isEmpty(); + } + + /* + * @see ICVSSynchronizer#members(File) + */ + public ResourceSyncInfo[] members(File folder) throws CVSException { + // read the entries file and cache if needed + Assert.isTrue(folder.exists()); + ResourceSyncInfo[] infos = SyncFileUtil.readEntriesFile(folder); + if(infos==null) { + return new ResourceSyncInfo[0]; + } else { + return infos; + } + } + + protected void destroySyncDeep(File file, IProgressMonitor monitor) { + if (file.isDirectory()) { + File[] fileList = file.listFiles(); + for (int i = 0; i < fileList.length; i++) { + destroySyncDeep(fileList[i], monitor); + } + folderSyncCache.remove(file); + File metaDir = SyncFileUtil.getCVSSubdirectory(file); + if(metaDir.exists()) { + FileUtil.deepDelete(metaDir); + } + } + deleteResourceSync(file); + } + + protected void clearCache(File file, int depth) { + if(file.exists()) { + if (file.isDirectory()) { + if(depth!=IResource.DEPTH_ZERO) { + File[] fileList = file.listFiles(); + for (int i = 0; i < fileList.length; i++) { + if(depth==IResource.DEPTH_ONE) { + depth = IResource.DEPTH_ZERO; + } + clearCache(fileList[i], depth); + } + } + folderSyncCache.remove(file); + } + resourceSyncCache.remove(file); + } else { + clearCacheForChildren(file); + } + } + + protected void clearCacheForChildren(File file) { + // XXX not optimal, could instead have implement the cache as a tree + // and be able to traverse children. This is the safest for now. + resourceSyncCache.clear(); + folderSyncCache.clear(); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FolderSyncInfo.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/FolderSyncInfo.java index 8e8effe03..bee61cd8c 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/FolderSyncInfo.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/FolderSyncInfo.java @@ -1,157 +1,158 @@ -package org.eclipse.team.internal.ccvs.core.resources;
-
-/*
- * (c) Copyright IBM Corp. 2000, 2001.
- * All Rights Reserved.
- */
-
-import org.eclipse.team.ccvs.core.CVSTag;
-import org.eclipse.team.internal.ccvs.core.CVSException;
-import org.eclipse.team.internal.ccvs.core.util.Assert;
-
-/**
- * Value (immutable) object that represents workspace state information about the contents of a
- * folder that was retreived from a CVS repository. It is a specialized representation of the files from
- * the CVS sub-directory that contain folder specific connection information (e.g. Root, Repository, Tag).
- *
- * @see ICVSFolder#getFolderSyncInfo()
- */
-public class FolderSyncInfo {
-
- // relative path of this folder in the repository, project1/folder1/folder2
- private String repository;
-
- // :pserver:user@host:/home/user/repo
- private String root;
-
- // sticky tag (e.g. version, date, or branch tag applied to folder)
- private CVSEntryLineTag tag;
-
- // if true then it means only part of the folder was fetched from the repository, and CVS will not create
- // additional files in that folder.
- private boolean isStatic;
-
- /**
- * Construct a folder sync object.
- *
- * @param repo the relative path of this folder in the repository, cannot be <code>null</code>.
- * @param root the location of the repository, cannot be <code>null</code>.
- * @param tag the tag set for the folder or <code>null</code> if there is no tag applied.
- * @param isStatic to indicate is only part of the folder was fetched from the server.
- */
- public FolderSyncInfo(String repo, String root, CVSTag tag, boolean isStatic) {
- Assert.isNotNull(repo);
- Assert.isNotNull(root);
- this.repository = repo;
- this.root = root;
- this.isStatic = isStatic;
- if(tag != null) {
- this.tag = new CVSEntryLineTag(tag);
- }
- }
-
- public boolean equals(Object other) {
- if(other == this) return true;
- if (!(other instanceof FolderSyncInfo)) return false;
-
- FolderSyncInfo syncInfo = ((FolderSyncInfo)other);
- if (!getRoot().equals(syncInfo.getRoot())) return false;
- if (!getRepository().equals(syncInfo.getRepository())) return false;
- if (getIsStatic() != syncInfo.getIsStatic()) return false;
- if ((getTag() == null) || (syncInfo.getTag() == null)) {
- if ((getTag() == null) && (syncInfo.getTag() != null) && (syncInfo.getTag().getType() != CVSTag.HEAD)) {
- return false;
- } else if ((syncInfo.getTag() == null) && (getTag() != null) && (getTag().getType() != CVSTag.HEAD)) {
- return false;
- }
- } else if (!getTag().equals(syncInfo.getTag())) {
- return false;
- }
- return true;
- }
- /**
- * Gets the root, cannot be <code>null.
- *
- * @return Returns a String
- */
- public String getRoot() {
- return root;
- }
-
- /**
- * Gets the tag, may be <code>null</code>.
- *
- * @return Returns a String
- */
- public CVSEntryLineTag getTag() {
- return tag;
- }
-
- /**
- * Gets the repository, may be <code>null</code>.
- *
- * @return Returns a String
- */
- public String getRepository() {
- return repository;
- }
-
- /**
- * Gets the isStatic.
- *
- * @return Returns a boolean
- */
- public boolean getIsStatic() {
- return isStatic;
- }
-
- /**
- * Answers a full path to the folder on the remote server. This by appending the repository to the
- * repository location speficied in the root.
- *
- * Example:
- * root = :pserver:user@host:/home/user/repo
- * repository = folder1/folder2
- *
- * Returns:
- * /home/users/repo/folder1/folder2
- *
- * @return the full path of this folder on the server.
- * @throws a CVSException if the root or repository is malformed.
- */
- public String getRemoteLocation() throws CVSException {
-
- String result;
-
- try {
- result = getRoot().substring(getRoot().indexOf("@")+1);
- result = result.substring(result.indexOf(":")+1);
- result = result + "/" + getRepository();
- } catch (IndexOutOfBoundsException e) {
- throw new CVSException("Maleformed root");
- }
-
- return result;
- }
-
- /*
- * Provide a hashCode() method that gaurentees that equal object will have the
- * same hashCode
- */
- public int hashCode() {
- return getRoot().hashCode() | getRepository().hashCode();
- }
-
- /**
- * Sets the tag for the folder.
- *
- * @param tag The tag to set
- */
- private void setTag(CVSTag tag) {
- if (tag == null) {
- this.tag = null;
- } else {
- this.tag = new CVSEntryLineTag(tag);
- }
- }
-}
+package org.eclipse.team.internal.ccvs.core.syncinfo; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ + +import org.eclipse.team.ccvs.core.CVSTag; +import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.resources.*; +import org.eclipse.team.internal.ccvs.core.util.Assert; + +/** + * Value (immutable) object that represents workspace state information about the contents of a + * folder that was retreived from a CVS repository. It is a specialized representation of the files from + * the CVS sub-directory that contain folder specific connection information (e.g. Root, Repository, Tag). + * + * @see ICVSFolder#getFolderSyncInfo() + */ +public class FolderSyncInfo { + + // relative path of this folder in the repository, project1/folder1/folder2 + private String repository; + + // :pserver:user@host:/home/user/repo + private String root; + + // sticky tag (e.g. version, date, or branch tag applied to folder) + private CVSEntryLineTag tag; + + // if true then it means only part of the folder was fetched from the repository, and CVS will not create + // additional files in that folder. + private boolean isStatic; + + /** + * Construct a folder sync object. + * + * @param repo the relative path of this folder in the repository, cannot be <code>null</code>. + * @param root the location of the repository, cannot be <code>null</code>. + * @param tag the tag set for the folder or <code>null</code> if there is no tag applied. + * @param isStatic to indicate is only part of the folder was fetched from the server. + */ + public FolderSyncInfo(String repo, String root, CVSTag tag, boolean isStatic) { + Assert.isNotNull(repo); + Assert.isNotNull(root); + this.repository = repo; + this.root = root; + this.isStatic = isStatic; + if(tag != null) { + this.tag = new CVSEntryLineTag(tag); + } + } + + public boolean equals(Object other) { + if(other == this) return true; + if (!(other instanceof FolderSyncInfo)) return false; + + FolderSyncInfo syncInfo = ((FolderSyncInfo)other); + if (!getRoot().equals(syncInfo.getRoot())) return false; + if (!getRepository().equals(syncInfo.getRepository())) return false; + if (getIsStatic() != syncInfo.getIsStatic()) return false; + if ((getTag() == null) || (syncInfo.getTag() == null)) { + if ((getTag() == null) && (syncInfo.getTag() != null) && (syncInfo.getTag().getType() != CVSTag.HEAD)) { + return false; + } else if ((syncInfo.getTag() == null) && (getTag() != null) && (getTag().getType() != CVSTag.HEAD)) { + return false; + } + } else if (!getTag().equals(syncInfo.getTag())) { + return false; + } + return true; + } + /** + * Gets the root, cannot be <code>null. + * + * @return Returns a String + */ + public String getRoot() { + return root; + } + + /** + * Gets the tag, may be <code>null</code>. + * + * @return Returns a String + */ + public CVSEntryLineTag getTag() { + return tag; + } + + /** + * Gets the repository, may be <code>null</code>. + * + * @return Returns a String + */ + public String getRepository() { + return repository; + } + + /** + * Gets the isStatic. + * + * @return Returns a boolean + */ + public boolean getIsStatic() { + return isStatic; + } + + /** + * Answers a full path to the folder on the remote server. This by appending the repository to the + * repository location speficied in the root. + * + * Example: + * root = :pserver:user@host:/home/user/repo + * repository = folder1/folder2 + * + * Returns: + * /home/users/repo/folder1/folder2 + * + * @return the full path of this folder on the server. + * @throws a CVSException if the root or repository is malformed. + */ + public String getRemoteLocation() throws CVSException { + + String result; + + try { + result = getRoot().substring(getRoot().indexOf("@")+1); + result = result.substring(result.indexOf(":")+1); + result = result + "/" + getRepository(); + } catch (IndexOutOfBoundsException e) { + throw new CVSException("Maleformed root"); + } + + return result; + } + + /* + * Provide a hashCode() method that gaurentees that equal object will have the + * same hashCode + */ + public int hashCode() { + return getRoot().hashCode() | getRepository().hashCode(); + } + + /** + * Sets the tag for the folder. + * + * @param tag The tag to set + */ + private void setTag(CVSTag tag) { + if (tag == null) { + this.tag = null; + } else { + this.tag = new CVSEntryLineTag(tag); + } + } +} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ICache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ICache.java new file mode 100644 index 000000000..a36ad9b06 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ICache.java @@ -0,0 +1,28 @@ +package org.eclipse.team.internal.ccvs.core.syncinfo; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +/** + * Interface for a simple cache. + */ +public interface ICache { + /** + * Returns a reference to the object associated with name. If the object name is not + * found in the cache, it is loaded by the loader defined for this cache. If a loader is + * not registered then <code>null</code> will be returned. + */ + public CacheData get(Object id, Object args); + + public void put(CacheData data); + + public void remove(Object id); + + public boolean isEmpty(); + + public void registerLoader(ICacheLoader loader); + + public void clear(); +}
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ICacheLoader.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ICacheLoader.java new file mode 100644 index 000000000..d748e1738 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ICacheLoader.java @@ -0,0 +1,20 @@ +package org.eclipse.team.internal.ccvs.core.syncinfo; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import org.eclipse.team.internal.ccvs.core.util.*; + +/** + * Interface for classes that can load an object from a store with the given id. + */ +public interface ICacheLoader { + /** + * Loads object associated with the given id from a store. The cache is passed so that if other objects + * are read as a side effect of fetching name, then they can automatically be added to the + * cache as well. + */ + public CacheData load(Object id, ICache cache); +} diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ResourceSyncInfo.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ResourceSyncInfo.java index ac663cf32..ce727133e 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/ResourceSyncInfo.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/ResourceSyncInfo.java @@ -1,370 +1,371 @@ -package org.eclipse.team.internal.ccvs.core.resources;
-
-/*
- * (c) Copyright IBM Corp. 2000, 2002.
- * All Rights Reserved.
- */
-
-import org.eclipse.team.ccvs.core.CVSTag;
-import org.eclipse.team.internal.ccvs.core.CVSException;
-import org.eclipse.team.internal.ccvs.core.util.Assert;
-import org.eclipse.team.internal.ccvs.core.util.EmptyTokenizer;
-
-/**
- * Value (immutable) object that represents workspace state information about a resource contained in
- * a CVS repository. It is a specialized representation of a line in the CVS/Entry file with the addition of
- * file permissions.
- *
- * Example entry line from the CVS/Entry file:
- *
- * /new.java/1.2/Fri Dec 07 00:17:52 2001/-kb/
- * D/src////
- *
- * @see ICVSResource#getSyncInfo()
- */
-public class ResourceSyncInfo {
-
- // a directory sync info will have nothing more than a name
- private boolean isDirectory = false;
-
- // utility constants
- private static final String DIRECTORY_PREFIX = "D/";
- public static final String BINARY_TAG = "-kb";
- private static final String SEPERATOR = "/";
-
- // Timestamp constants used to identify special cases
- public static final String DUMMY_TIMESTAMP = "dummy timestamp";
- public static final String RESULT_OF_MERGE = "Result of merge+";
-
- // safe default permissions. Permissions are saved separatly so that the correct permissions
- // can be sent back to the server on systems that don't save execute bits (e.g. windows).
- public static final String DEFAULT_PERMISSIONS = "u=rw,g=rw,o=r";
-
- // file sync information can be associated with a local resource that has been deleted. This is
- // noted by prefixing the revision with this character.
- // XXX Should this be private
- static final String DELETED_PREFIX = "-";
- private boolean isDeleted = false;
-
- // a sync element with a revision of '0' is considered a new file that has
- // not been comitted to the repo. Is visible so that clients can create sync infos
- // for new files.
- public static final String ADDED_REVISION = "0";
-
- // fields describing the synchronization of a resource in CVS parlance
- private String name;
- private String revision;
- private String timeStamp;
- private String keywordMode;
- private CVSEntryLineTag tag;
- private String permissions;
-
- /**
- * Constructor to create a sync object from entry line formats. The entry lines are parsed by this class.
- *
- * @param entryLine the entry line (e.g. /new.java/1.2/Fri Dec 07 00:17:52 2001/-kb/)
- * @param permissions the file permission (e.g. u=rw,g=rw,o=r). May be <code>null</code>.
- * @param timestamp if not included in the entry line. Will overide the value in the entry line. The
- * timestamp should be in the format specified in ICVSFile#getTimestamp(). May be <code>null</code>.
- *
- * @exception CVSException is thrown if the entry cannot be parsed.
- */
- public ResourceSyncInfo(String entryLine, String permissions, String timestamp) throws CVSException {
- Assert.isNotNull(entryLine);
-
- setEntryLine(entryLine);
-
- if (permissions != null) {
- this.permissions = permissions;
- }
- // override the timestamp that may of been in entryLine. In some cases the timestamp is not in the
- // entry line (e.g. receiving entry lines from the server versus reading them from the Entry file).
- if(timestamp!=null) {
- this.timeStamp = timestamp;
- }
- }
-
- /**
- * Constructor to create a sync object from predefined values.
- *
- * @param name of the resource for which this sync state is associated, cannot be <code>null</code>.
- * @param revision of the resource, cannot be <code>null</code>.
- * @param timestamp can be <code>null</code>.
- * @param keywordMode can be <code>null</code>
- * @param tag can be <code>null</code>
- * @param permissions can be <code>null</code>
- */
- public ResourceSyncInfo(String name, String revision, String timestamp, String keywordMode, CVSTag tag, String permissions) {
- Assert.isNotNull(name);
- Assert.isNotNull(revision);
- this.name = name;
- this.timeStamp = timestamp;
- this.keywordMode = keywordMode;
- this.permissions = permissions;
- setRevision(revision);
- setTag(tag);
- }
-
- /**
- * Constructor to create a folder sync object.
- *
- * @param name of the resource for which this sync state is associatied, cannot be <code>null</code>.
- */
- public ResourceSyncInfo(String name) {
- Assert.isNotNull(name);
- this.name = name;
- this.isDirectory = true;
- }
-
- /**
- * Answers if this sync information is for a folder in which case only a name is
- * available.
- *
- * @return <code>true</code> if the sync information is for a folder and <code>false</code>
- * if it is for a file.
- */
- public boolean isDirectory() {
- return isDirectory;
- }
-
- /**
- * Answers if this sync information is for a file that has been added but not comitted
- * to the CVS repository yet.
- *
- * @return <code>true</code> if the sync information is new or <code>false</code> if
- * the sync is for an file that exists remotely. For folder sync info this returns
- * <code>false</code>.
- */
- public boolean isAdded() {
- if(!isDirectory) {
- return getRevision().equals(ADDED_REVISION);
- } else {
- return false;
- }
- }
-
- /**
- * Answers if this sync information is for a file that is scheduled to be deleted
- * from the repository but the deletion has not yet been comitted.
- *
- * @return <code>true</code> if the sync information is deleted or <code>false</code> if
- * the sync is for an file that exists remotely.
- */
- public boolean isDeleted() {
- return isDeleted;
- }
-
- /**
- * Answers a CVS compatible entry line. The client can use this line to store in the CVS/Entry file or
- * sent it to the server.
- *
- * @param includeTimeStamp determines if the timestamp will be included in the returned entry line. In
- * some usages the timestamp should not be included in entry lines, for example when sending the entries
- * to the server.
- *
- * @return a file or folder entry line reflecting the state of this sync object.
- */
- public String getEntryLine(boolean includeTimeStamp) {
-
- StringBuffer result = new StringBuffer();
-
- if(isDirectory) {
- result.append(DIRECTORY_PREFIX);
- result.append(name + "////");
- } else {
- result.append(SEPERATOR);
- result.append(name);
- result.append(SEPERATOR);
-
- if(isDeleted){
- result.append(DELETED_PREFIX);
- }
-
- result.append(revision);
- result.append(SEPERATOR);
-
- if(includeTimeStamp) {
- result.append(timeStamp);
- }
- result.append(SEPERATOR);
- result.append(keywordMode == null ? "" : keywordMode);
- result.append(SEPERATOR);
- if (tag != null) {
- result.append(tag.toEntryLineFormat(true));
- }
- }
-
- return result.toString();
- }
-
- /**
- * Anwsers the a compatible permissions line for files.
- *
- * @return a permission line for files and <code>null</code> if this sync object is
- * a directory.
- */
- public String getPermissionLine() {
- if(isDirectory) {
- return null;
- } else {
- String permissions = this.permissions;
- if (permissions == null)
- permissions = DEFAULT_PERMISSIONS;
- return SEPERATOR + name + SEPERATOR + permissions;
- }
- }
-
- /**
- * Gets the permissions or <code>null</code> if permissions are not available.
- *
- * @return a string of the format "u=rw,g=rw,o=r"
- */
- public String getPermissions() {
- if(isDirectory) {
- return null;
- } else {
- if(permissions==null) {
- return DEFAULT_PERMISSIONS;
- } else {
- return permissions;
- }
- }
- }
-
- /**
- * Gets the tag or <code>null</code> if a tag is not available.
- *
- * @return Returns a String
- */
- public CVSTag getTag() {
- return tag;
- }
-
- /**
- * Gets the timeStamp or <code>null</code> if a timestamp is not available.
- *
- * @return a string of the format "Thu Oct 18 20:21:13 2001"
- */
- public String getTimeStamp() {
- return timeStamp;
- }
-
- /**
- * Gets the version or <code>null</code> if this is a folder sync info. The returned
- * revision will never include the DELETED_PREFIX. To found out if this sync info is
- * for a deleted resource call isDeleted().
- *
- * @return Returns a String
- */
- public String getRevision() {
- return revision;
- }
-
-
- /**
- * Gets the name.
- *
- * @return Returns a String
- */
- public String getName() {
- return name;
- }
-
- /**
- * Gets the keyword mode or <code>null</code> if a keyword mode is available.
- *
- * @return
- */
- public String getKeywordMode() {
- return keywordMode;
- }
-
- /**
- * Name equality between resource sync info objects.
- */
- public boolean equals(Object other) {
- if(other instanceof ResourceSyncInfo) {
- ResourceSyncInfo syncInfo = ((ResourceSyncInfo)other);
- if(other == this) return true;
- if(getName() == syncInfo.getName()) return true;
- return getName().equals(syncInfo.getName());
- } else {
- return false;
- }
- }
-
- public int hashCode() {
- return getName().hashCode();
- }
-
- /**
- * Sets the tag for the resource.
- */
- private void setTag(CVSTag tag) {
- if(tag!=null) {
- this.tag = new CVSEntryLineTag(tag);
- } else {
- this.tag = null;
- }
- }
-
- /**
- * Set the entry line
- *
- * @throws CVSException if the entryLine is malformed
- */
- private void setEntryLine(String entryLine) throws CVSException {
- if(entryLine.startsWith(DIRECTORY_PREFIX)) {
- isDirectory = true;
- entryLine = entryLine.substring(1);
- } else {
- isDirectory = false;
- }
-
- EmptyTokenizer tokenizer = new EmptyTokenizer(entryLine,SEPERATOR);
-
- if(tokenizer.countTokens() != 5) {
- throw new CVSException("Malformed entry line: " + entryLine);
- }
-
- name = tokenizer.nextToken();
-
- if(name.length()==0) {
- throw new CVSException("Malformed entry line, missing name: " + entryLine);
- }
-
- String rev = tokenizer.nextToken();
-
- if(rev.length()==0 && !isDirectory()) {
- throw new CVSException("Malformed entry line, missing revision: " + entryLine);
- } else {
- setRevision(rev);
- }
-
- timeStamp = tokenizer.nextToken();
- keywordMode = tokenizer.nextToken();
- String tagEntry = tokenizer.nextToken();
-
- if(tagEntry.length()>0) {
- tag = new CVSEntryLineTag(tagEntry);
- } else {
- tag = null;
- }
- }
-
- /**
- * Sets the version and decides if the revision is for a deleted resource the revision field
- * will not include the deleted prefix '-'.
- *
- * @param version the version to set
- */
- private void setRevision(String revision) {
- if(revision.startsWith(DELETED_PREFIX)) {
- this.revision = revision.substring(DELETED_PREFIX.length());
- isDeleted = true;
- } else {
- this.revision = revision;
- isDeleted = false;
- }
- }
+package org.eclipse.team.internal.ccvs.core.syncinfo; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import org.eclipse.team.ccvs.core.CVSTag; +import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.resources.*; +import org.eclipse.team.internal.ccvs.core.util.Assert; +import org.eclipse.team.internal.ccvs.core.util.EmptyTokenizer; + +/** + * Value (immutable) object that represents workspace state information about a resource contained in + * a CVS repository. It is a specialized representation of a line in the CVS/Entry file with the addition of + * file permissions. + * + * Example entry line from the CVS/Entry file: + * + * /new.java/1.2/Fri Dec 07 00:17:52 2001/-kb/ + * D/src//// + * + * @see ICVSResource#getSyncInfo() + */ +public class ResourceSyncInfo { + + // a directory sync info will have nothing more than a name + private boolean isDirectory = false; + + // utility constants + private static final String DIRECTORY_PREFIX = "D/"; + public static final String BINARY_TAG = "-kb"; + private static final String SEPERATOR = "/"; + + // Timestamp constants used to identify special cases + public static final String DUMMY_TIMESTAMP = "dummy timestamp"; + public static final String RESULT_OF_MERGE = "Result of merge+"; + + // safe default permissions. Permissions are saved separatly so that the correct permissions + // can be sent back to the server on systems that don't save execute bits (e.g. windows). + public static final String DEFAULT_PERMISSIONS = "u=rw,g=rw,o=r"; + + // file sync information can be associated with a local resource that has been deleted. This is + // noted by prefixing the revision with this character. + // XXX Should this be private + public static final String DELETED_PREFIX = "-"; + private boolean isDeleted = false; + + // a sync element with a revision of '0' is considered a new file that has + // not been comitted to the repo. Is visible so that clients can create sync infos + // for new files. + public static final String ADDED_REVISION = "0"; + + // fields describing the synchronization of a resource in CVS parlance + private String name; + private String revision; + private String timeStamp; + private String keywordMode; + private CVSEntryLineTag tag; + private String permissions; + + /** + * Constructor to create a sync object from entry line formats. The entry lines are parsed by this class. + * + * @param entryLine the entry line (e.g. /new.java/1.2/Fri Dec 07 00:17:52 2001/-kb/) + * @param permissions the file permission (e.g. u=rw,g=rw,o=r). May be <code>null</code>. + * @param timestamp if not included in the entry line. Will overide the value in the entry line. The + * timestamp should be in the format specified in ICVSFile#getTimestamp(). May be <code>null</code>. + * + * @exception CVSException is thrown if the entry cannot be parsed. + */ + public ResourceSyncInfo(String entryLine, String permissions, String timestamp) throws CVSException { + Assert.isNotNull(entryLine); + + setEntryLine(entryLine); + + if (permissions != null) { + this.permissions = permissions; + } + // override the timestamp that may of been in entryLine. In some cases the timestamp is not in the + // entry line (e.g. receiving entry lines from the server versus reading them from the Entry file). + if(timestamp!=null) { + this.timeStamp = timestamp; + } + } + + /** + * Constructor to create a sync object from predefined values. + * + * @param name of the resource for which this sync state is associated, cannot be <code>null</code>. + * @param revision of the resource, cannot be <code>null</code>. + * @param timestamp can be <code>null</code>. + * @param keywordMode can be <code>null</code> + * @param tag can be <code>null</code> + * @param permissions can be <code>null</code> + */ + public ResourceSyncInfo(String name, String revision, String timestamp, String keywordMode, CVSTag tag, String permissions) { + Assert.isNotNull(name); + Assert.isNotNull(revision); + this.name = name; + this.timeStamp = timestamp; + this.keywordMode = keywordMode; + this.permissions = permissions; + setRevision(revision); + setTag(tag); + } + + /** + * Constructor to create a folder sync object. + * + * @param name of the resource for which this sync state is associatied, cannot be <code>null</code>. + */ + public ResourceSyncInfo(String name) { + Assert.isNotNull(name); + this.name = name; + this.isDirectory = true; + } + + /** + * Answers if this sync information is for a folder in which case only a name is + * available. + * + * @return <code>true</code> if the sync information is for a folder and <code>false</code> + * if it is for a file. + */ + public boolean isDirectory() { + return isDirectory; + } + + /** + * Answers if this sync information is for a file that has been added but not comitted + * to the CVS repository yet. + * + * @return <code>true</code> if the sync information is new or <code>false</code> if + * the sync is for an file that exists remotely. For folder sync info this returns + * <code>false</code>. + */ + public boolean isAdded() { + if(!isDirectory) { + return getRevision().equals(ADDED_REVISION); + } else { + return false; + } + } + + /** + * Answers if this sync information is for a file that is scheduled to be deleted + * from the repository but the deletion has not yet been comitted. + * + * @return <code>true</code> if the sync information is deleted or <code>false</code> if + * the sync is for an file that exists remotely. + */ + public boolean isDeleted() { + return isDeleted; + } + + /** + * Answers a CVS compatible entry line. The client can use this line to store in the CVS/Entry file or + * sent it to the server. + * + * @param includeTimeStamp determines if the timestamp will be included in the returned entry line. In + * some usages the timestamp should not be included in entry lines, for example when sending the entries + * to the server. + * + * @return a file or folder entry line reflecting the state of this sync object. + */ + public String getEntryLine(boolean includeTimeStamp) { + + StringBuffer result = new StringBuffer(); + + if(isDirectory) { + result.append(DIRECTORY_PREFIX); + result.append(name + "////"); + } else { + result.append(SEPERATOR); + result.append(name); + result.append(SEPERATOR); + + if(isDeleted){ + result.append(DELETED_PREFIX); + } + + result.append(revision); + result.append(SEPERATOR); + + if(includeTimeStamp) { + result.append(timeStamp); + } + result.append(SEPERATOR); + result.append(keywordMode == null ? "" : keywordMode); + result.append(SEPERATOR); + if (tag != null) { + result.append(tag.toEntryLineFormat(true)); + } + } + + return result.toString(); + } + + /** + * Anwsers the a compatible permissions line for files. + * + * @return a permission line for files and <code>null</code> if this sync object is + * a directory. + */ + public String getPermissionLine() { + if(isDirectory) { + return null; + } else { + String permissions = this.permissions; + if (permissions == null) + permissions = DEFAULT_PERMISSIONS; + return SEPERATOR + name + SEPERATOR + permissions; + } + } + + /** + * Gets the permissions or <code>null</code> if permissions are not available. + * + * @return a string of the format "u=rw,g=rw,o=r" + */ + public String getPermissions() { + if(isDirectory) { + return null; + } else { + if(permissions==null) { + return DEFAULT_PERMISSIONS; + } else { + return permissions; + } + } + } + + /** + * Gets the tag or <code>null</code> if a tag is not available. + * + * @return Returns a String + */ + public CVSTag getTag() { + return tag; + } + + /** + * Gets the timeStamp or <code>null</code> if a timestamp is not available. + * + * @return a string of the format "Thu Oct 18 20:21:13 2001" + */ + public String getTimeStamp() { + return timeStamp; + } + + /** + * Gets the version or <code>null</code> if this is a folder sync info. The returned + * revision will never include the DELETED_PREFIX. To found out if this sync info is + * for a deleted resource call isDeleted(). + * + * @return Returns a String + */ + public String getRevision() { + return revision; + } + + + /** + * Gets the name. + * + * @return Returns a String + */ + public String getName() { + return name; + } + + /** + * Gets the keyword mode or <code>null</code> if a keyword mode is available. + * + * @return + */ + public String getKeywordMode() { + return keywordMode; + } + + /** + * Name equality between resource sync info objects. + */ + public boolean equals(Object other) { + if(other instanceof ResourceSyncInfo) { + ResourceSyncInfo syncInfo = ((ResourceSyncInfo)other); + if(other == this) return true; + if(getName() == syncInfo.getName()) return true; + return getName().equals(syncInfo.getName()); + } else { + return false; + } + } + + public int hashCode() { + return getName().hashCode(); + } + + /** + * Sets the tag for the resource. + */ + private void setTag(CVSTag tag) { + if(tag!=null) { + this.tag = new CVSEntryLineTag(tag); + } else { + this.tag = null; + } + } + + /** + * Set the entry line + * + * @throws CVSException if the entryLine is malformed + */ + private void setEntryLine(String entryLine) throws CVSException { + if(entryLine.startsWith(DIRECTORY_PREFIX)) { + isDirectory = true; + entryLine = entryLine.substring(1); + } else { + isDirectory = false; + } + + EmptyTokenizer tokenizer = new EmptyTokenizer(entryLine,SEPERATOR); + + if(tokenizer.countTokens() != 5) { + throw new CVSException("Malformed entry line: " + entryLine); + } + + name = tokenizer.nextToken(); + + if(name.length()==0) { + throw new CVSException("Malformed entry line, missing name: " + entryLine); + } + + String rev = tokenizer.nextToken(); + + if(rev.length()==0 && !isDirectory()) { + throw new CVSException("Malformed entry line, missing revision: " + entryLine); + } else { + setRevision(rev); + } + + timeStamp = tokenizer.nextToken(); + keywordMode = tokenizer.nextToken(); + String tagEntry = tokenizer.nextToken(); + + if(tagEntry.length()>0) { + tag = new CVSEntryLineTag(tagEntry); + } else { + tag = null; + } + } + + /** + * Sets the version and decides if the revision is for a deleted resource the revision field + * will not include the deleted prefix '-'. + * + * @param version the version to set + */ + private void setRevision(String revision) { + if(revision.startsWith(DELETED_PREFIX)) { + this.revision = revision.substring(DELETED_PREFIX.length()); + isDeleted = true; + } else { + this.revision = revision; + isDeleted = false; + } + } }
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/SimpleCache.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/SimpleCache.java new file mode 100644 index 000000000..6cb3c6863 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/SimpleCache.java @@ -0,0 +1,76 @@ +package org.eclipse.team.internal.ccvs.core.syncinfo; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.util.HashMap; +import java.util.Map; + +/** + * A simple implementation of a cache. If a id is not in the cache it can be loaded via the loaded + * registered with the cache instance. + */ +public class SimpleCache implements ICache { + + private Map cache = new HashMap(); + private ICacheLoader loader; + private boolean cleanUpCache = false; + + /* + * @see ICache#get(Object, Object) + */ + public CacheData get(Object id, Object args) { + CacheData data = (CacheData)cache.get(id); + if(data==null && loader!=null) { + data = loader.load(id, this); + if(data!=null) { + put(data); + } + } + return data; + } + + /* + * @see ICache#put(Object, Object) + */ + public void put(CacheData data) { + cache.put(data.getId(), data); + } + + /* + * @see ICache#remove(Object) + */ + public void remove(Object id) { + cache.remove(id); + } + + /* + * @see ICache#isEmpty() + */ + public boolean isEmpty() { + return cache.isEmpty(); + } + + /* + * @see ICache#registerLoader(ICacheLoader) + */ + public void registerLoader(ICacheLoader loader) { + this.loader = loader; + } + + /* + * @see ICache#setAutoInvalidate(boolean) + */ + public void setAutoInvalidate(boolean enable) { + cleanUpCache = true; + } + + /* + * @see ICache#clear() + */ + public void clear() { + cache.clear(); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ListFileFilter.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ListFileFilter.java deleted file mode 100644 index e11a9487a..000000000 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ListFileFilter.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.eclipse.team.internal.ccvs.core.util;
-
-/*
- * (c) Copyright IBM Corp. 2000, 2001.
- * All Rights Reserved.
- */
-
-import java.io.File;
-import java.io.FileFilter;
-import org.eclipse.team.internal.ccvs.core.util.Assert;
-import sun.audio.ContinuousAudioDataStream;
-
-/**
- * This class is a default FileFilter, that is used to
- * ex- or include certain files on a ioFile.listFiles.
- *
- * @see java.io.FileFilter
- */
-public class ListFileFilter implements FileFilter {
-
- private final String[] fileNameList;
- private final boolean exclude;
- private final boolean fileOnly;
- private final boolean folderOnly;
-
- /**
- * @param fileNameList the list of fileNames you want to include or exclude
- * @param exclude if true all files not in fileNameList are shown
- if false only files in fileNameList are shown
- */
- public ListFileFilter(String[] fileNameList, boolean exclude) {
- this(fileNameList,exclude,false, false);
- }
-
- /**
- * @param fileNameList the list of fileNames you want to include or exclude
- * @param exclude if true all files not in fileNameList are shown
- if false only files in fileNameList are shown
- * @param fileOnly if true only files are shown
- * @param folderOnly if true only folders are shown
- */
- public ListFileFilter(String[] fileNameList, boolean exclude, boolean fileOnly, boolean folderOnly) {
-
- Assert.isTrue(!fileOnly || !folderOnly);
-
- if (fileNameList == null) {
- fileNameList = new String[0];
- }
-
- this.fileNameList = fileNameList;
- this.exclude = exclude;
- this.fileOnly = fileOnly;
- this.folderOnly = folderOnly;
- }
-
- /**
- * @see FileFilter#accept(File)
- */
- public boolean accept(File file) {
-
- boolean result = exclude;
- String fileName = file.getName();
-
- // If the resource is of the wrong type reject it
- if (fileOnly && file.isDirectory()) {
- return false;
- }
- if (folderOnly && file.isFile()) {
- return false;
- }
-
- for (int i=0; i<fileNameList.length; i++) {
- // use starts-with because we do not want to be
- // messed up by an following seperator
- if (fileName.startsWith(fileNameList[i])) {
- result = !result;
- break;
- }
- }
-
- return result;
- }
-}
-
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/RemoteFolderTreeBuilder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/RemoteFolderTreeBuilder.java index deed86950..ea4aa6ec2 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/RemoteFolderTreeBuilder.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/RemoteFolderTreeBuilder.java @@ -33,14 +33,15 @@ import org.eclipse.team.internal.ccvs.core.client.listeners.StatusListener; import org.eclipse.team.internal.ccvs.core.client.listeners.UpdateListener;
import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation;
import org.eclipse.team.internal.ccvs.core.connection.CVSServerException;
-import org.eclipse.team.internal.ccvs.core.resources.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.core.resources.ICVSFile;
import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder;
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.RemoteFolderTree;
import org.eclipse.team.internal.ccvs.core.resources.RemoteResource;
-import org.eclipse.team.internal.ccvs.core.resources.ResourceSyncInfo;
+import org.eclipse.team.internal.ccvs.core.syncinfo.*;
+import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
+import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
import org.omg.CORBA.UNKNOWN;
/*
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaVisitor.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaVisitor.java index 09623d412..ebc00b40e 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaVisitor.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/ResourceDeltaVisitor.java @@ -1,7 +1,7 @@ package org.eclipse.team.internal.ccvs.core.util; /* - * (c) Copyright IBM Corp. 2000, 2002. + * (c) Copyright IBM Corp. 2000, 2001. * All Rights Reserved. */ @@ -23,9 +23,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.team.ccvs.core.CVSTeamProvider; import org.eclipse.team.core.ITeamProvider; import org.eclipse.team.core.TeamPlugin; -import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.Policy; -import org.eclipse.team.internal.ccvs.core.resources.ICVSFolder; public abstract class ResourceDeltaVisitor implements IResourceDeltaVisitor { @@ -43,40 +41,31 @@ public abstract class ResourceDeltaVisitor implements IResourceDeltaVisitor { listener = new IResourceChangeListener() { public void resourceChanged(IResourceChangeEvent event) { try { - if (event.getType() == IResourceChangeEvent.PRE_DELETE) { - // We add the removal in the pre-delete. - // It will be forwarded when we get the post change - IResource resource = event.getResource(); + IResourceDelta root = event.getDelta(); + IResourceDelta[] projectDeltas = root.getAffectedChildren(); + for (int i = 0; i < projectDeltas.length; i++) { + IResourceDelta delta = projectDeltas[i]; + IResource resource = delta.getResource(); ITeamProvider provider = TeamPlugin.getManager().getProvider(resource); - if (provider instanceof CVSTeamProvider) - addRemoval(resource.getProject(), resource); - } else { - IResourceDelta root = event.getDelta(); - IResourceDelta[] projectDeltas = root.getAffectedChildren(); - for (int i = 0; i < projectDeltas.length; i++) { - IResourceDelta delta = projectDeltas[i]; - IResource resource = delta.getResource(); - ITeamProvider provider = TeamPlugin.getManager().getProvider(resource); - - // if a project is moved the originating project will not be associated with the CVS provider - // however listeners will probably still be interested in the move delta. - if ((delta.getFlags() & IResourceDelta.MOVED_TO) > 0) { - IResource destination = getResourceFor(resource.getProject(), resource, delta.getMovedToPath()); - provider = TeamPlugin.getManager().getProvider(destination); - } - - if (provider instanceof CVSTeamProvider) { - delta.accept(visitor); - } + + // if a project is moved the originating project will not be associated with the CVS provider + // however listeners will probably still be interested in the move delta. + if ((delta.getFlags() & IResourceDelta.MOVED_TO) > 0) { + IResource destination = getResourceFor(resource.getProject(), resource, delta.getMovedToPath()); + provider = TeamPlugin.getManager().getProvider(destination); + } + + if (provider instanceof CVSTeamProvider) { + delta.accept(visitor); } - visitor.handle(); } + visitor.handle(); } catch (CoreException e) { Util.logError(Policy.bind("ResourceDeltaVisitor.visitError"), e); } } }; - ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_DELETE); + ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE); return visitor; } @@ -161,6 +150,8 @@ public abstract class ResourceDeltaVisitor implements IResourceDeltaVisitor { handleChanged(changes); changes.clear(); + + finished(); } /** @@ -176,13 +167,8 @@ public abstract class ResourceDeltaVisitor implements IResourceDeltaVisitor { Iterator i = additions.keySet().iterator(); while (i.hasNext()) { IProject project = (IProject)i.next(); - ITeamProvider provider = TeamPlugin.getManager().getProvider(project); - Iterator j = ((List)additions.get(project)).iterator(); - while (j.hasNext()) { - IResource resource = (IResource)j.next(); - handleAdded(project,resource); - //System.out.println(resource.toString()); - } + ArrayList resources = (ArrayList)additions.get(project); + handleAdded((IResource[])resources.toArray(new IResource[additions.size()])); } } @@ -199,13 +185,8 @@ public abstract class ResourceDeltaVisitor implements IResourceDeltaVisitor { Iterator i = changes.keySet().iterator(); while (i.hasNext()) { IProject project = (IProject)i.next(); - ITeamProvider provider = TeamPlugin.getManager().getProvider(project); - Iterator j = ((List)changes.get(project)).iterator(); - while (j.hasNext()) { - IResource resource = (IResource)j.next(); - handleChanged(project,resource); - //System.out.println(resource.toString()); - } + ArrayList resources = (ArrayList)changes.get(project); + handleChanged((IResource[])resources.toArray(new IResource[changes.size()])); } } @@ -221,29 +202,26 @@ public abstract class ResourceDeltaVisitor implements IResourceDeltaVisitor { Iterator i = removals.keySet().iterator(); while (i.hasNext()) { IProject project = (IProject)i.next(); - ITeamProvider provider = TeamPlugin.getManager().getProvider(project); - Iterator j = ((List)removals.get(project)).iterator(); - while (j.hasNext()) { - IResource resource = (IResource)j.next(); - handleRemoved(project,resource); - //System.out.println(resource.toString()); - } + ArrayList resources = (ArrayList)removals.get(project); + handleRemoved((IResource[])resources.toArray(new IResource[removals.size()])); } } /** * React on every addition */ - protected abstract void handleAdded(IProject project,IResource resource); + protected abstract void handleAdded(IResource[] resources); /** * React on every removal */ - protected abstract void handleRemoved(IProject project,IResource resource); + protected abstract void handleRemoved(IResource[] resources); /** * React on every change */ - protected abstract void handleChanged(IProject project,IResource resource); + protected abstract void handleChanged(IResource[] resources); + protected abstract void finished(); } + diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileUtil.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileUtil.java index 7b00620fc..60f516a35 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileUtil.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileUtil.java @@ -3,7 +3,7 @@ package org.eclipse.team.internal.ccvs.core.util; import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
-import java.io.FileFilter;
+import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
@@ -13,17 +13,18 @@ import java.util.List; import java.util.Map;
import java.util.TreeMap;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.team.ccvs.core.CVSTag;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.resources.CVSEntryLineTag;
-import org.eclipse.team.internal.ccvs.core.resources.FolderSyncInfo;
-import org.eclipse.team.internal.ccvs.core.resources.ResourceSyncInfo;
+import org.eclipse.team.internal.ccvs.core.syncinfo.*;
+import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
+import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
public class SyncFileUtil {
- // CVS meta files located in CVS sub-directory of folders that are managed by CVS. These
- // files contain the workspace revision information for the resources that have been
- // checked out into a CVS workspace. See the CVS documentation for more details.
+ // All possible files available in the CVS subdir
+
public static final String REPOSITORY = "Repository";
public static final String ROOT = "Root";
public static final String STATIC = "Entries.Static";
@@ -35,6 +36,10 @@ public class SyncFileUtil { // Some older CVS clients may of added a line to the entries file consisting
// of only a 'D'. It is safe to ingnore these entries.
private static final String FOLDER_TAG="D";
+
+ // Command characters found in the Entries.log file
+ private static final String ADD_TAG="A ";
+ private static final String REMOVE_TAG="R ";
/**
* Reads the CVS/Entry and CVS/Permissions files for the given folder. If the folder does not have a
@@ -88,6 +93,56 @@ public class SyncFileUtil { return (ResourceSyncInfo[])infos.values().toArray(new ResourceSyncInfo[infos.size()]);
}
+ public static void writeResourceSync(File file, ResourceSyncInfo info) throws CVSException {
+ writeEntriesLog(file, info, ADD_TAG);
+ }
+
+ /**
+ * Append to Entries.log file
+ */
+ private static void writeEntriesLog(File file, ResourceSyncInfo info, String prefix) throws CVSException {
+ FileOutputStream out = null;
+ try {
+ File entriesLogFile = new File(getCVSSubdirectory(file.getParentFile()), ENTRIES_LOG);
+ if(!entriesLogFile.exists()) {
+ entriesLogFile.createNewFile();
+ }
+ String line = prefix + info.getEntryLine(true) +"\n";
+ out = new FileOutputStream(entriesLogFile.getAbsolutePath(), true);
+ out.write(line.getBytes());
+ } catch(IOException e) {
+ throw new CVSException(IStatus.ERROR, 0, "Error writing to Entries.log.", e);
+ } finally {
+ try {
+ if(out!=null) {
+ out.close();
+ }
+ } catch(IOException e) {
+ throw new CVSException(IStatus.ERROR, 0, "Cannot close Entries.log.", e);
+ }
+ }
+ }
+
+ /**
+ * Delete this file from Entries/Permissions file
+ */
+ public static void deleteSync(File file) throws CVSException {
+ if(file.isDirectory()) {
+ writeEntriesLog(file, new ResourceSyncInfo(file.getName()), REMOVE_TAG);
+ } else {
+ writeEntriesLog(file, new ResourceSyncInfo(file.getName(), "0", "", "", null, ""), REMOVE_TAG);
+ }
+ }
+
+ public static boolean isMetaFile(File file) {
+ File parent = file.getParentFile();
+ if(parent!=null&&parent.getName().equals("CVS")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
/**
* Writes the given resource sync infos into the CVS/Entry and CVS/Permissions files.
*/
@@ -139,6 +194,16 @@ public class SyncFileUtil { return new FolderSyncInfo(repo, root, cvsTag, isStatic);
}
+ public static File[] getEntrySyncFiles(File folder) {
+ File cvsSubDir = getCVSSubdirectory(folder);
+ return new File[] { new File(cvsSubDir, ENTRIES), new File(cvsSubDir, PERMISSIONS) };
+ }
+
+ public static File[] getFolderSyncFiles(File folder) {
+ File cvsSubDir = getCVSSubdirectory(folder);
+ return new File[] { new File(cvsSubDir, ROOT), new File(cvsSubDir, REPOSITORY), new File(cvsSubDir, STATIC), new File(cvsSubDir, TAG) };
+ }
+
public static void writeFolderConfig(File parent, FolderSyncInfo info) throws CVSException {
if(!getCVSSubdirectory(parent).exists()) {
@@ -147,11 +212,7 @@ public class SyncFileUtil { writeLine(parent, ROOT, info.getRoot());
if (info.getTag() != null) {
- String tagString = info.getTag().toEntryLineFormat(false);
- if (tagString.length() > 0)
- writeLine(parent, TAG, tagString);
- else
- writeLine(parent, TAG, null);
+ writeLine(parent, TAG, info.getTag().toEntryLineFormat(false));
} else {
writeLine(parent, TAG, null);
}
@@ -162,20 +223,6 @@ public class SyncFileUtil { }
writeLine(parent, REPOSITORY, info.getRepository());
}
-
- public static File[] getEntrySyncFiles(File folder) {
- File cvsSubDir = getCVSSubdirectory(folder);
- return new File[] { new File(cvsSubDir, ENTRIES), new File(cvsSubDir, PERMISSIONS) };
- }
-
- public static File[] getFolderSyncFiles(File folder) {
- File cvsSubDir = getCVSSubdirectory(folder);
- return new File[] {new File(cvsSubDir, ROOT), new File(cvsSubDir, REPOSITORY), new File(cvsSubDir, STATIC), new File(cvsSubDir, TAG)};
- }
-
- public static File getCVSSubdirectory(File folder) {
- return new File(folder, "CVS");
- }
protected static void setContents(File parent, String filename, String[] contents) throws CVSException {
@@ -216,61 +263,14 @@ public class SyncFileUtil { } else {
return null;
}
- }
+ }
- /**
- * To be compatible with other CVS clients meta files must be written with lines
- * terminating with a carriage return only.
- */
- private static void writeLines(File file, String[] content) throws CVSException {
-
- BufferedWriter fileWriter;
-
- try {
- fileWriter = new BufferedWriter(new FileWriter(file));
- for (int i = 0; i<content.length; i++) {
- fileWriter.write(content[i] + "\n");
- }
- fileWriter.close();
- } catch (IOException e) {
- throw CVSException.wrapException(e);
- }
+ public static File getCVSSubdirectory(File folder) {
+ return new File(folder, "CVS");
}
- public static String[] readLines(File file) throws CVSException {
- BufferedReader fileReader;
- List fileContentStore = new ArrayList();
- String line;
-
- try {
- fileReader = new BufferedReader(new FileReader(file));
- while ((line = fileReader.readLine()) != null) {
- fileContentStore.add(line);
- }
- fileReader.close();
- } catch (IOException e) {
- throw CVSException.wrapException(e);
- }
-
- return (String[]) fileContentStore.toArray(new String[fileContentStore.size()]);
- }
-
public static void mergeEntriesLogFiles(File root) throws CVSException {
- String FOLDER_TAG="D";
- String ADD_TAG="A ";
- String REMOVE_TAG="R ";
-
- File[] dirs = root.listFiles(new FileFilter() {
- public boolean accept(File file) {
- return file.isDirectory() && !file.getName().equals("CVS");
- }
- });
-
- //for (int i = 0; i < dirs.length; i++) {
- // mergeEntriesLogFiles(dirs[i]); - //}
-
File logEntriesFile = new File(getCVSSubdirectory(root), ENTRIES_LOG);
File entriesFile = new File(getCVSSubdirectory(root), ENTRIES);
@@ -287,11 +287,13 @@ public class SyncFileUtil { Map mergedEntries = new HashMap();
- String[] entries = readLines(entriesFile);
- for (int i = 0; i < entries.length; i++) {
- if (!FOLDER_TAG.equals(entries[i])) {
- mergedEntries.put((new ResourceSyncInfo(entries[i],null, null)).getName(),entries[i]);
- } + if(entriesFile.exists()) {
+ String[] entries = readLines(entriesFile);
+ for (int i = 0; i < entries.length; i++) {
+ if (!FOLDER_TAG.equals(entries[i])) {
+ mergedEntries.put((new ResourceSyncInfo(entries[i],null, null)).getName(),entries[i]);
+ } + }
}
String[] logEntries = readLines(logEntriesFile);
@@ -309,4 +311,41 @@ public class SyncFileUtil { writeLines(entriesFile,(String[]) mergedEntries.values().toArray(new String[mergedEntries.size()]));
logEntriesFile.delete();
}
+
+ public static String[] readLines(File file) throws CVSException {
+ BufferedReader fileReader;
+ List fileContentStore = new ArrayList();
+ String line;
+
+ try {
+ fileReader = new BufferedReader(new FileReader(file));
+ while ((line = fileReader.readLine()) != null) {
+ fileContentStore.add(line);
+ }
+ fileReader.close();
+ } catch (IOException e) {
+ throw CVSException.wrapException(e);
+ }
+
+ return (String[]) fileContentStore.toArray(new String[fileContentStore.size()]);
+ }
+
+ /**
+ * To be compatible with other CVS clients meta files must be written with lines
+ * terminating with a carriage return only.
+ */
+ private static void writeLines(File file, String[] content) throws CVSException {
+
+ BufferedWriter fileWriter;
+
+ try {
+ fileWriter = new BufferedWriter(new FileWriter(file));
+ for (int i = 0; i<content.length; i++) {
+ fileWriter.write(content[i] + "\n");
+ }
+ fileWriter.close();
+ } catch (IOException e) {
+ throw CVSException.wrapException(e);
+ }
+ }
}
\ No newline at end of file |