1 /*******************************************************************************
2  * Copyright (c) 2000, 2010 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.team.internal.ccvs.ui.operations;
15 
16 import org.eclipse.core.resources.*;
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.osgi.util.NLS;
19 import org.eclipse.swt.widgets.Shell;
20 import org.eclipse.team.core.RepositoryProvider;
21 import org.eclipse.team.core.TeamException;
22 import org.eclipse.team.internal.ccvs.core.*;
23 import org.eclipse.team.internal.ccvs.core.client.Command;
24 import org.eclipse.team.internal.ccvs.core.client.Session;
25 import org.eclipse.team.internal.ccvs.core.connection.CVSServerException;
26 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
27 import org.eclipse.team.internal.ccvs.core.resources.RemoteFolderTree;
28 import org.eclipse.team.internal.ccvs.ui.CVSUIMessages;
29 import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
30 import org.eclipse.team.internal.ccvs.ui.Policy;
31 
32 /**
33  * Create a folder and any missing parents in the repository
34  */
35 public class ShareProjectOperation extends CVSOperation {
36 
37 	private ICVSRepositoryLocation location;
38 	private IProject project;
39 	private String moduleName;
40 	private Shell shell;
41 
ShareProjectOperation(Shell shell, ICVSRepositoryLocation location, IProject project, String moduleName)42 	public ShareProjectOperation(Shell shell, ICVSRepositoryLocation location, IProject project, String moduleName) {
43 		super(null);
44 		this.shell = shell;
45 		this.moduleName = moduleName;
46 		this.project = project;
47 		this.location = location;
48 	}
49 
50 	@Override
execute(IProgressMonitor monitor)51 	protected void execute(IProgressMonitor monitor) throws CVSException, InterruptedException {
52 		try {
53 			monitor.beginTask(getTaskName(), 100);
54 			// Create the remote module
55 			final ICVSRemoteFolder remote = createRemoteFolder(Policy.subMonitorFor(monitor, 50));
56 			// Map the project to the module in a workspace runnable
57 			final TeamException[] exception = new TeamException[] {null};
58 			ResourcesPlugin.getWorkspace().run((IWorkspaceRunnable) monitor1 -> {
59 				try {
60 					mapProjectToRemoteFolder(remote, monitor1);
61 				} catch (TeamException e) {
62 					exception[0] = e;
63 				}
64 			}, ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(project), 0, Policy.subMonitorFor(monitor, 100));
65 			if (exception[0] != null)
66 				throw exception[0];
67 		} catch (CoreException e) {
68 			throw CVSException.wrapException(e);
69 		} finally {
70 			monitor.done();
71 		}
72 	}
73 
74 	/**
75 	 * Create the remote folder to which the project is being mapped
76 	 * (as well as any ancestors) and return it. If the remote folder does not
77 	 * exist remotely, this method will create it.
78 	 * @param monitor a progress monitor
79 	 * @return the existing remote folder to which the project is being mapped
80 	 * @throws CVSException
81 	 */
createRemoteFolder(IProgressMonitor monitor)82 	protected ICVSRemoteFolder createRemoteFolder(IProgressMonitor monitor) throws CVSException {
83 		String projectName = project.getName();
84 		if (moduleName == null)
85 			moduleName = projectName;
86 
87 		RemoteFolderTree root = new RemoteFolderTree(null, location, Path.EMPTY.toString(), null);
88 		Path path = new Path(null, moduleName);
89 
90 		try {
91 			monitor.beginTask(getTaskName(), 100 * path.segmentCount());
92 			return ensureTreeExists(root, path, monitor);
93 		} catch (TeamException e) {
94 			throw CVSException.wrapException(e);
95 		} finally {
96 			monitor.done();
97 		}
98 	}
99 
100 	/**
101 	 * Map the project to the remote folder by associating the CVS
102 	 * Repository Provider with the project and, at the very least,
103 	 * assigning the folder sync info for the remote folder as the
104 	 * folder sync info for the project.
105 	 * @param remote the remote folder to which the project is being mapped
106 	 * @param monitor a progress monitor
107 	 * @throws CVSException
108 	 */
mapProjectToRemoteFolder(final ICVSRemoteFolder remote, IProgressMonitor monitor)109 	protected void mapProjectToRemoteFolder(final ICVSRemoteFolder remote, IProgressMonitor monitor) throws TeamException {
110 		monitor.beginTask(null, IProgressMonitor.UNKNOWN);
111 		purgeAnyCVSFolders(Policy.subMonitorFor(monitor, IProgressMonitor.UNKNOWN));
112 		// Link the project to the newly created module
113 		monitor.subTask(NLS.bind(CVSUIMessages.ShareProjectOperation_3, new String[] { project.getName(), remote.getRepositoryRelativePath() }));
114 		ICVSFolder folder = (ICVSFolder)CVSWorkspaceRoot.getCVSResourceFor(project);
115 		folder.setFolderSyncInfo(remote.getFolderSyncInfo());
116 		//Register it with Team.  If it already is, no harm done.
117 		RepositoryProvider.map(project, CVSProviderPlugin.getTypeId());
118 		monitor.done();
119 	}
120 
121 	/*
122 	 * Create handles for all the children in the moduleName path
123 	 */
createChild(RemoteFolderTree parent, String name, IProgressMonitor monitor)124 	private RemoteFolderTree createChild(RemoteFolderTree parent, String name, IProgressMonitor monitor) throws CVSException, TeamException {
125 		RemoteFolderTree child = new RemoteFolderTree(parent, name, location, new Path(null, parent.getRepositoryRelativePath()).append(name).toString(), null);
126 		parent.setChildren(new ICVSRemoteResource[] { child });
127 		if (child.exists(Policy.subMonitorFor(monitor, 50))) {
128 			// The child exists so get the handle that was received from the server
129 			return (RemoteFolderTree)parent.getFolder(name);
130 		} else {
131 			// Create the folder remotely
132 			createFolder(child, Policy.subMonitorFor(monitor, 50));
133 			return child;
134 		}
135 	}
136 
137 	/*
138 	 * Ensure that all the folders in the tree exist
139 	 */
ensureTreeExists(RemoteFolderTree folder, IPath path, IProgressMonitor monitor)140 	private ICVSRemoteFolder ensureTreeExists(RemoteFolderTree folder, IPath path, IProgressMonitor monitor) throws TeamException {
141 		if (path.isEmpty()) return folder;
142 		String name = path.segment(0);
143 		RemoteFolderTree child = createChild(folder, name, monitor);
144 		return ensureTreeExists(child, path.removeFirstSegments(1), monitor);
145 	}
146 
createFolder(RemoteFolderTree folder, IProgressMonitor monitor)147 	private void createFolder(RemoteFolderTree folder, IProgressMonitor monitor) throws TeamException {
148 		Session s = new Session(location, folder.getParent());
149 		s.open(monitor, true /* open for modification */);
150 		try {
151 			IStatus status = Command.ADD.execute(s,
152 					Command.NO_GLOBAL_OPTIONS,
153 					Command.NO_LOCAL_OPTIONS,
154 					new String[] { folder.getName() },
155 					null,
156 					monitor);
157 			// If we get a warning, the operation most likely failed so check that the status is OK
158 			if (status.getCode() == CVSStatus.SERVER_ERROR  || ! status.isOK()) {
159 				throw new CVSServerException(status);
160 			}
161 		} finally {
162 			s.close();
163 		}
164 	}
165 
166 	@Override
getTaskName()167 	protected String getTaskName() {
168 		return NLS.bind(CVSUIMessages.ShareProjectOperation_0, new String[] { project.getName(), moduleName });
169 	}
170 
171 	/**
172 	 * @return Returns the project.
173 	 */
getProject()174 	public IProject getProject() {
175 		return project;
176 	}
177 
178 	@Override
getShell()179 	public Shell getShell() {
180 		return shell;
181 	}
182 
183 	/**
184 	 * Purge any CVS folders.
185 	 *
186 	 * @param monitor a progress monitor
187 	 */
purgeAnyCVSFolders(final IProgressMonitor monitor)188 	private void purgeAnyCVSFolders(final IProgressMonitor monitor) {
189 		try {
190 			monitor.beginTask(null, IProgressMonitor.UNKNOWN);
191 			ICVSFolder folder = CVSWorkspaceRoot.getCVSFolderFor(project);
192 			folder.accept(new ICVSResourceVisitor() {
193 				@Override
194 				public void visitFile(ICVSFile file) throws CVSException {
195 					// nothing to do for files
196 				}
197 				@Override
198 				public void visitFolder(ICVSFolder folder) throws CVSException {
199 					monitor.subTask(NLS.bind(CVSUIMessages.ShareProjectOperation_2, new String[] { folder.getIResource().getFullPath().toString() } ));
200 					if (folder.isCVSFolder()) {
201 						// for now, just unmanage
202 						folder.unmanage(null);
203 					}
204 				}
205 			}, true /* recurse */);
206 		} catch (CVSException e) {
207 			// log the exception and return null
208 			CVSUIPlugin.log(e);
209 		} finally {
210 			monitor.done();
211 		}
212 	}
213 }
214