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