1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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.core.resources;
15 
16 import org.eclipse.core.resources.*;
17 import org.eclipse.core.runtime.IProgressMonitor;
18 import org.eclipse.core.runtime.IStatus;
19 import org.eclipse.osgi.util.NLS;
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.connection.CVSRepositoryLocation;
24 import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
25 import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
26 import org.eclipse.team.internal.ccvs.core.util.KnownRepositories;
27 import org.eclipse.team.internal.ccvs.core.util.Util;
28 
29 /**
30  * This class provides static methods for checking out projects from a repository
31  * into the local workspace and for converting IResources into CVSRespources
32  * and sync trees.
33  * Instances of this class represent a local workspace root (i.e. a project).
34  */
35 public class CVSWorkspaceRoot {
36 
37 	private ICVSFolder localRoot;
38 
CVSWorkspaceRoot(IContainer resource)39 	public CVSWorkspaceRoot(IContainer resource){
40 		this.localRoot = getCVSFolderFor(resource);
41 	}
42 
43 	/**
44 	 * Set the sharing for a project to enable it to be used with the CVSTeamProvider.
45 	 * This method ensure that the repository in the FolderSyncInfo is known and that
46 	 * the project is mapped to a CVS repository provider. It does not modify the sync
47 	 * info associated with the project's resources in any way.
48 	 */
setSharing(IProject project, FolderSyncInfo info, IProgressMonitor monitor)49 	public static void setSharing(IProject project, FolderSyncInfo info, IProgressMonitor monitor) throws TeamException {
50 
51 		// Ensure provided info matches that of the project
52 		ICVSFolder folder = (ICVSFolder)CVSWorkspaceRoot.getCVSResourceFor(project);
53 		FolderSyncInfo folderInfo = folder.getFolderSyncInfo();
54 		if ( ! info.equals(folderInfo)) {
55 			throw new CVSException(new CVSStatus(IStatus.ERROR, NLS.bind(CVSMessages.CVSProvider_infoMismatch, new String[] { project.getName() })));
56 		}
57 
58 		// Ensure that the repository location format is supported
59 		String root = info.getRoot();
60 		// This will try to create a repository location for the root.
61 		// If it fails, an exception is thrown.
62 		KnownRepositories.getInstance().getRepository(root);
63 
64 		// Register the project with Team
65 		RepositoryProvider.map(project, CVSProviderPlugin.getTypeId());
66 	}
67 
getCVSFolderFor(IContainer resource)68 	public static ICVSFolder getCVSFolderFor(IContainer resource) {
69 		return new EclipseFolder(resource);
70 	}
71 
72 
getCVSFileFor(IFile resource)73 	public static ICVSFile getCVSFileFor(IFile resource) {
74 		return new EclipseFile(resource);
75 	}
76 
77 
getCVSResourceFor(IResource resource)78 	public static ICVSResource getCVSResourceFor(IResource resource) {
79 		if (resource.getType() == IResource.FILE)
80 			return getCVSFileFor((IFile) resource);
81 		else
82 			return getCVSFolderFor((IContainer) resource);
83 	}
84 
getRemoteResourceFor(IResource resource)85 	public static ICVSRemoteResource getRemoteResourceFor(IResource resource) throws CVSException {
86 		ICVSResource managed = getCVSResourceFor(resource);
87 		return getRemoteResourceFor(managed);
88 	}
89 
getRemoteResourceFor(ICVSResource resource)90 	public static ICVSRemoteResource getRemoteResourceFor(ICVSResource resource) throws CVSException {
91 		if (resource.isFolder()) {
92 			ICVSFolder folder = (ICVSFolder)resource;
93 			FolderSyncInfo syncInfo = folder.getFolderSyncInfo();
94 			if (syncInfo != null) {
95 				return new RemoteFolder(null, KnownRepositories.getInstance().getRepository(syncInfo.getRoot()), syncInfo.getRepository(), syncInfo.getTag());
96 			}
97 		} else {
98 			if (resource.isManaged()) {
99 				RemoteFolder parent = (RemoteFolder)getRemoteResourceFor(resource.getParent());
100 				if (parent == null) {
101 					// This could be caused by another thread changing the state in the
102 					// instant between when we did the managed check and we obtained the
103 					// parent handle. If this is the case, isManaged should return false
104 					// now. If it doesn't, then we should log an error.
105 					if (resource.isManaged()) {
106 						CVSProviderPlugin.log(new CVSStatus(IStatus.ERROR,CVSStatus.ERROR, NLS.bind(CVSMessages.CVSWorkspaceRoot_11, new String[] { Util.getFullestPath(resource) }),resource.getIResource()));
107 					}
108 				} else {
109 					return RemoteFile.getBase(parent, (ICVSFile)resource);
110 				}
111 			}
112 		}
113 		return null;
114 	}
115 
116 	/*
117 	 * Helper method that uses the parent of a local resource that has no base to ensure that the resource
118 	 * wasn't added remotely by a third party
119 	 */
getRemoteTreeFromParent(IResource resource, ICVSResource managed, CVSTag tag, IProgressMonitor progress)120 	private static ICVSRemoteResource getRemoteTreeFromParent(IResource resource, ICVSResource managed, CVSTag tag, IProgressMonitor progress) throws TeamException {
121 		// If the parent isn't mapped to CVS, there's nothing we can do
122 		ICVSFolder parent = managed.getParent();
123 		FolderSyncInfo syncInfo = parent.getFolderSyncInfo();
124 		if (syncInfo == null) {
125 			// The parent is managed so just indicate that there is no remote
126 			return null;
127 		}
128 		ICVSRepositoryLocation location = KnownRepositories.getInstance().getRepository(parent.getFolderSyncInfo().getRoot());
129 		RemoteFolder remoteParent = RemoteFolderTreeBuilder.buildRemoteTree((CVSRepositoryLocation)location, parent, tag, progress);
130 		ICVSRemoteResource remote = null;
131 		if (remoteParent != null) {
132 			try {
133 				remote = (ICVSRemoteResource)remoteParent.getChild(resource.getName());
134 			} catch (CVSException e) {
135 				remote = null;
136 			}
137 			// The types need to match or we're in trouble
138 			if (remote != null && !(remote.isContainer() == managed.isFolder()))
139 				throw new CVSException(new CVSStatus(IStatus.ERROR, CVSStatus.ERROR, NLS.bind(CVSMessages.CVSTeamProvider_typesDiffer, new String[] { resource.getFullPath().toString() }), resource));
140 		}
141 		return remote;
142 	}
143 
144 	/**
145 	 * Return the remote tree that corresponds to the given local resource. Return
146 	 * <code>null</code> if the remote tree doesn't exist remotely or if the local
147 	 * resource is not mapped to a remote (i.e. is not managed by CVS).
148 	 *
149 	 * @param resource the local resource
150 	 * @param tag the tag to be queried remotely
151 	 * @param cacheFileContentsHint hint which indicates whether file contents will be required
152 	 * @param depth the depth
153 	 * @param progress
154 	 * @return the remote tree or <code>null</code>
155 	 * @throws TeamException
156 	 */
getRemoteTree(IResource resource, CVSTag tag, boolean cacheFileContentsHint, int depth, IProgressMonitor progress)157 	public static ICVSRemoteResource getRemoteTree(IResource resource, CVSTag tag, boolean cacheFileContentsHint, int depth, IProgressMonitor progress) throws TeamException {
158 		ICVSResource managed = CVSWorkspaceRoot.getCVSResourceFor(resource);
159 		ICVSRemoteResource remote = CVSWorkspaceRoot.getRemoteResourceFor(resource);
160 		if (remote == null) {
161 			progress.beginTask(null, 100);
162 			remote = getRemoteTreeFromParent(resource, managed, tag, Policy.subMonitorFor(progress, 50));
163 			if (cacheFileContentsHint && remote != null && remote instanceof RemoteFile) {
164 				RemoteFile file = (RemoteFile)remote;
165 				// get the storage for the file to ensure that the contents are cached
166 				file.getStorage(Policy.subMonitorFor(progress, 50));
167 			}
168 			progress.done();
169 		} else if(resource.getType() == IResource.FILE) {
170 			ICVSRepositoryLocation location = remote.getRepository();
171 			if (cacheFileContentsHint) {
172 				remote = UpdateContentCachingService.buildRemoteTree((CVSRepositoryLocation)location, (ICVSFile)managed, tag, progress);
173 			} else {
174 				remote = RemoteFolderTreeBuilder.buildRemoteTree((CVSRepositoryLocation)location, (ICVSFile)managed, tag, progress);
175 			}
176 		} else {
177 			ICVSRepositoryLocation location = remote.getRepository();
178 			if (cacheFileContentsHint) {
179 				remote = UpdateContentCachingService.buildRemoteTree((CVSRepositoryLocation)location, (ICVSFolder)managed, tag, depth, progress);
180 			} else {
181 				remote = RemoteFolderTreeBuilder.buildRemoteTree((CVSRepositoryLocation)location, (ICVSFolder)managed, tag, progress);
182 			}
183 		}
184 		return remote;
185 	}
186 
hasRemote(IResource resource)187 	public static boolean hasRemote(IResource resource) {
188 		try {
189 			ICVSResource cvsResource = getCVSResourceFor(resource);
190 			int type = resource.getType();
191 			if(type!=IResource.FILE) {
192 				if(type==IResource.PROJECT) {
193 					return ((ICVSFolder)cvsResource).isCVSFolder();
194 				} else {
195 					return cvsResource.isManaged();
196 				}
197 			} else {
198 				byte[] syncBytes = ((ICVSFile)cvsResource).getSyncBytes();
199 				if(syncBytes!=null) {
200 					return !ResourceSyncInfo.isAddition(syncBytes);
201 				} else {
202 					return false;
203 				}
204 			}
205 		} catch(CVSException e) {
206 			return false;
207 		}
208 	}
209 
getRemoteLocation()210 	public ICVSRepositoryLocation getRemoteLocation() throws CVSException {
211 		FolderSyncInfo info = localRoot.getFolderSyncInfo();
212 		if (info == null) {
213 			IStatus status = new CVSStatus(IStatus.ERROR,CVSStatus.RESOURCE_SYNC_INFO_ERROR,NLS.bind(CVSMessages.CVSWorkspaceRoot_notCVSFolder, new String[] { localRoot.getName() }),localRoot);
214 			throw new CVSException(status);
215 		}
216 		return KnownRepositories.getInstance().getRepository(info.getRoot());
217 	}
218 
getLocalRoot()219 	public ICVSFolder getLocalRoot() {
220 		return localRoot;
221 	}
222 
223 
224 	/**
225 	 * Return true if the resource is part of a link (i.e. a linked resource or
226 	 * one of it's children.
227 	 *
228 	 * @param container
229 	 * @return boolean
230 	 */
isLinkedResource(IResource resource)231 	public static boolean isLinkedResource(IResource resource) {
232 		return resource.isLinked(IResource.CHECK_ANCESTORS);
233 	}
234 
235 	/**
236 	 * A resource is considered shared
237 	 * @param resource
238 	 * @return boolean
239 	 */
isSharedWithCVS(IResource resource)240 	public static boolean isSharedWithCVS(IResource resource) throws CVSException {
241 		if (!resource.isAccessible()) return false;
242 		if(isLinkedResource(resource)) return false;
243 
244 		if(RepositoryProvider.getProvider(resource.getProject(), CVSProviderPlugin.getTypeId()) == null) {
245 			return false;
246 		}
247 
248 		ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource);
249 		if (cvsResource.isManaged()) return true;
250 		if (!cvsResource.exists()) return false;
251 		if (cvsResource.isFolder() && ((ICVSFolder) cvsResource).isCVSFolder()) return true;
252 		if (cvsResource.isIgnored()) return false;
253 		return cvsResource.getParent().isCVSFolder();
254 	}
255 
256 	/**
257 	 * Return whether the given container is an orphaned subtree. An orphaned subtree
258 	 * is folder (i.e. non-project) that is a CVS folder but is not managed and is not
259 	 * a linked resource. To know if the resource is a descendant of an orphaned subtree,
260 	 * the client must invoked this method for each ancestor of a resource.
261 	 * @param container the container being tested
262 	 * @return whether the container is an orphaned CVS folder
263 	 * @throws CVSException
264 	 */
isOrphanedSubtree(IContainer container)265 	public static boolean isOrphanedSubtree(IContainer container) throws CVSException {
266 		ICVSFolder mFolder = CVSWorkspaceRoot.getCVSFolderFor(container);
267 		return (mFolder.isCVSFolder()
268 				&& ! mFolder.isManaged()
269 				&& mFolder.getIResource().getType() == IResource.FOLDER
270 				&& !isLinkedResource(container));
271 	}
272 }
273