Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSubscriberOperation.java')
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSubscriberOperation.java314
1 files changed, 314 insertions, 0 deletions
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSubscriberOperation.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSubscriberOperation.java
new file mode 100644
index 000000000..ee24e199c
--- /dev/null
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/subscriber/CVSSubscriberOperation.java
@@ -0,0 +1,314 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.team.internal.ccvs.ui.subscriber;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+import org.eclipse.compare.structuremergeviewer.IDiffElement;
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.team.core.TeamException;
+import org.eclipse.team.core.synchronize.SyncInfo;
+import org.eclipse.team.core.synchronize.SyncInfoSet;
+import org.eclipse.team.core.variants.IResourceVariant;
+import org.eclipse.team.internal.ccvs.core.*;
+import org.eclipse.team.internal.ccvs.core.client.PruneFolderVisitor;
+import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
+import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer;
+import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
+import org.eclipse.team.internal.ccvs.ui.Policy;
+import org.eclipse.team.internal.ui.TeamUIPlugin;
+import org.eclipse.team.internal.ui.actions.SubscriberOperation;
+import org.eclipse.ui.IWorkbenchPart;
+
+public abstract class CVSSubscriberOperation extends SubscriberOperation {
+
+ protected CVSSubscriberOperation(IWorkbenchPart part, IDiffElement[] elements) {
+ super(part, elements);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ // Divide the sync info by project
+ final Map projectSyncInfos = getProjectSyncInfoSetMap();
+ for (Iterator iter = projectSyncInfos.keySet().iterator(); iter.hasNext(); ) {
+ final IProject project = (IProject) iter.next();
+ try {
+ // Pass the scheduling rule to the synchronizer so that sync change events
+ // and cache commits to disk are batched
+ EclipseSynchronizer.getInstance().run(
+ project,
+ new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ try {
+ CVSSubscriberOperation.this.run((SyncInfoSet)projectSyncInfos.get(project), monitor);
+ } catch (TeamException e) {
+ throw CVSException.wrapException(e);
+ }
+ }
+ }, monitor);
+ } catch (TeamException e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+ }
+
+ /**
+ * Run the operation on the sync info in the given set. The sync info will be all
+ * from the same project.
+ * @param set the sync info set
+ * @param monitor a progress monitor
+ */
+ protected abstract void run(SyncInfoSet set, IProgressMonitor monitor) throws TeamException;
+
+ /*
+ * Indicate that the resource is out of sync if the sync state is not IN_SYNC
+ * or if the local doesn't exist but the remote does.
+ */
+ protected boolean isOutOfSync(SyncInfo resource) {
+ if (resource == null) return false;
+ return (!(resource.getKind() == 0) ||
+ (! resource.getLocal().exists() && resource.getRemote() != null));
+ }
+
+ protected void makeInSync(SyncInfo[] folders) throws TeamException {
+ // If a node has a parent that is an incoming folder creation, we have to
+ // create that folder locally and set its sync info before we can get the
+ // node itself. We must do this for all incoming folder creations (recursively)
+ // in the case where there are multiple levels of incoming folder creations.
+ for (int i = 0; i < folders.length; i++) {
+ SyncInfo resource = folders[i];
+ makeInSync(resource);
+ }
+ }
+
+ protected boolean makeInSync(SyncInfo info) throws TeamException {
+ if (isOutOfSync(info)) {
+ SyncInfo parent = getParent(info);
+ if (parent == null) {
+ if (info.getLocal().getType() == IResource.ROOT) {
+ // ROOT should be null
+ return true;
+ } else {
+ // No other ancestors should be null. Log the problem.
+ CVSUIPlugin.log(IStatus.WARNING, Policy.bind("CVSSubscriberAction.0", info.getLocal().getFullPath().toString()), null); //$NON-NLS-1$
+ return false;
+ }
+ } else {
+ if (!makeInSync(parent)) {
+ // The failed makeInSync will log any errors
+ return false;
+ }
+ }
+ if (info instanceof CVSSyncInfo) {
+ CVSSyncInfo cvsInfo= (CVSSyncInfo) info;
+ IStatus status = cvsInfo.makeInSync();
+ if (status.getSeverity() == IStatus.ERROR) {
+ logError(status);
+ return false;
+ }
+ return true;
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ protected void makeOutgoing(SyncInfo[] folders, IProgressMonitor monitor) throws TeamException {
+ // If a node has a parent that is an incoming folder creation, we have to
+ // create that folder locally and set its sync info before we can get the
+ // node itself. We must do this for all incoming folder creations (recursively)
+ // in the case where there are multiple levels of incoming folder creations.
+ monitor.beginTask(null, 100 * folders.length);
+ for (int i = 0; i < folders.length; i++) {
+ SyncInfo info = folders[i];
+ makeOutgoing(info, Policy.subMonitorFor(monitor, 100));
+ }
+ monitor.done();
+ }
+
+ private void makeOutgoing(SyncInfo info, IProgressMonitor monitor) throws TeamException {
+ if (info == null) return;
+ if (info instanceof CVSSyncInfo) {
+ CVSSyncInfo cvsInfo= (CVSSyncInfo) info;
+ IStatus status = cvsInfo.makeOutgoing(monitor);
+ if (status.getSeverity() == IStatus.ERROR) {
+ logError(status);
+ }
+ }
+ }
+
+ /**
+ * Log an error associated with an operation.
+ * @param status
+ */
+ protected void logError(IStatus status) {
+ CVSUIPlugin.log(status);
+ }
+
+ /**
+ * Handle the exception by showing an error dialog to the user.
+ * Sync actions seem to need to be sync-execed to work
+ * @param t
+ */
+ protected void handle(Exception t) {
+ CVSUIPlugin.openError(getShell(), getErrorTitle(), null, t, CVSUIPlugin.PERFORM_SYNC_EXEC | CVSUIPlugin.LOG_NONTEAM_EXCEPTIONS);
+ }
+
+ /**
+ * Return the error title that will appear in any error dialogs shown to the user
+ * @return
+ */
+ protected String getErrorTitle() {
+ return null;
+ }
+
+ protected boolean canRunAsJob() {
+ return true;
+ }
+
+ protected void pruneEmptyParents(SyncInfo[] nodes) throws CVSException {
+ // TODO: A more explicit tie in to the pruning mechanism would be prefereable.
+ // i.e. I don't like referencing the option and visitor directly
+ if (!CVSProviderPlugin.getPlugin().getPruneEmptyDirectories()) return;
+ ICVSResource[] cvsResources = new ICVSResource[nodes.length];
+ for (int i = 0; i < cvsResources.length; i++) {
+ cvsResources[i] = CVSWorkspaceRoot.getCVSResourceFor(nodes[i].getLocal());
+ }
+ new PruneFolderVisitor().visit(
+ CVSWorkspaceRoot.getCVSFolderFor(ResourcesPlugin.getWorkspace().getRoot()),
+ cvsResources);
+ }
+
+ public CVSSyncInfo getCVSSyncInfo(SyncInfo info) {
+ if (info instanceof CVSSyncInfo) {
+ return (CVSSyncInfo)info;
+ }
+ return null;
+ }
+
+ protected SyncInfo getParent(SyncInfo info) throws TeamException {
+ return ((CVSSyncInfo)info).getSubscriber().getSyncInfo(info.getLocal().getParent());
+ }
+
+ protected IResource[] getIResourcesFrom(SyncInfo[] nodes) {
+ List resources = new ArrayList(nodes.length);
+ for (int i = 0; i < nodes.length; i++) {
+ resources.add(nodes[i].getLocal());
+ }
+ return (IResource[]) resources.toArray(new IResource[resources.size()]);
+ }
+
+ /**
+ * Prompt to overwrite those resources that could not be safely updated
+ * Note: This method is designed to be overridden by test cases.
+ *
+ * @return whether to perform the overwrite
+ */
+ protected boolean promptForOverwrite(final SyncInfoSet syncSet) {
+ final int[] result = new int[] {Dialog.CANCEL};
+ TeamUIPlugin.getStandardDisplay().syncExec(new Runnable() {
+ public void run() {
+ UpdateDialog dialog = new UpdateDialog(getShell(), syncSet);
+ result[0] = dialog.open();
+ }
+ });
+ return (result[0] == UpdateDialog.YES);
+ }
+
+ /**
+ * Make the contents of the local resource match that of the remote
+ * without modifying the sync info of the local resource.
+ * If called on a new folder, the sync info will be copied.
+ */
+ protected void makeRemoteLocal(SyncInfo info, IProgressMonitor monitor) throws TeamException {
+ IResourceVariant remote = info.getRemote();
+ IResource local = info.getLocal();
+ try {
+ if(remote==null) {
+ if (local.exists()) {
+ local.delete(IResource.KEEP_HISTORY, monitor);
+ }
+ } else {
+ if(remote.isContainer()) {
+ ensureContainerExists(info);
+ } else {
+ monitor.beginTask(null, 200);
+ try {
+ IFile localFile = (IFile)local;
+ if(local.exists()) {
+ localFile.setContents(remote.getStorage(Policy.subMonitorFor(monitor, 100)).getContents(), false /*don't force*/, true /*keep history*/, Policy.subMonitorFor(monitor, 100));
+ } else {
+ ensureContainerExists(getParent(info));
+ localFile.create(remote.getStorage(Policy.subMonitorFor(monitor, 100)).getContents(), false /*don't force*/, Policy.subMonitorFor(monitor, 100));
+ }
+ } finally {
+ monitor.done();
+ }
+ }
+ }
+ } catch(CoreException e) {
+ throw new CVSException(Policy.bind("UpdateMergeActionProblems_merging_remote_resources_into_workspace_1"), e); //$NON-NLS-1$
+ }
+ }
+
+ private boolean ensureContainerExists(SyncInfo info) throws TeamException {
+ IResource local = info.getLocal();
+ // make sure that the parent exists
+ if (!local.exists()) {
+ if (!ensureContainerExists(getParent(info))) {
+ return false;
+ }
+ }
+ // make sure that the folder sync info is set;
+ if (isOutOfSync(info)) {
+ if (info instanceof CVSSyncInfo) {
+ CVSSyncInfo cvsInfo = (CVSSyncInfo)info;
+ IStatus status = cvsInfo.makeInSync();
+ if (status.getSeverity() == IStatus.ERROR) {
+ logError(status);
+ return false;
+ }
+ }
+ }
+ // create the folder if it doesn't exist
+ ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor((IContainer)local);
+ if (!cvsFolder.exists()) {
+ cvsFolder.mkdir();
+ }
+ return true;
+ }
+
+ /*
+ * Divide the sync info for the operation by project
+ */
+ private Map getProjectSyncInfoSetMap() {
+ Map map = new HashMap();
+ SyncInfoSet all = getSyncInfoSet();
+ SyncInfo[] infos = all.getSyncInfos();
+ for (int i = 0; i < infos.length; i++) {
+ SyncInfo info = infos[i];
+ IProject project = info.getLocal().getProject();
+ SyncInfoSet set = (SyncInfoSet)map.get(project);
+ if (set == null) {
+ set = new SyncInfoSet();
+ map.put(project, set);
+ }
+ set.add(info);
+ }
+ return map;
+ }
+}

Back to the top