Copyright (c) 2000, 2015 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Serge Beauchamp (Freescale Semiconductor) - [229633] Project Path Variable Support
/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Serge Beauchamp (Freescale Semiconductor) - [229633] Project Path Variable Support *******************************************************************************/
package org.eclipse.core.internal.resources; import java.net.URI; import org.eclipse.core.filesystem.*; import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.internal.localstore.FileSystemResourceManager; import org.eclipse.core.internal.properties.IPropertyManager; import org.eclipse.core.internal.utils.*; import org.eclipse.core.resources.*; import org.eclipse.core.resources.team.IResourceTree; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.jobs.ILock; import org.eclipse.osgi.util.NLS;
Since:2.0 Implementation note: Since the move/delete hook involves running third party code, the workspace lock is not held. This means the workspace lock must be re-acquired whenever we need to manipulate the workspace in any way. All entry points from third party code back into the tree must be done in an acquire/release pair.
/** * @since 2.0 * * Implementation note: Since the move/delete hook involves running third * party code, the workspace lock is not held. This means the workspace * lock must be re-acquired whenever we need to manipulate the workspace * in any way. All entry points from third party code back into the tree must * be done in an acquire/release pair. */
class ResourceTree implements IResourceTree { private boolean isValid = true; private final FileSystemResourceManager localManager;
The lock to acquire when the workspace needs to be manipulated
/** * The lock to acquire when the workspace needs to be manipulated */
private ILock lock; private MultiStatus multistatus; private int updateFlags;
Constructor for this class.
/** * Constructor for this class. */
public ResourceTree(FileSystemResourceManager localManager, ILock lock, MultiStatus status, int updateFlags) { super(); this.localManager = localManager; this.lock = lock; this.multistatus = status; this.updateFlags = updateFlags; }
See Also:
  • addToLocalHistory.addToLocalHistory(IFile)
/** * @see IResourceTree#addToLocalHistory(IFile) */
@Override public void addToLocalHistory(IFile file) { Assert.isLegal(isValid); try { lock.acquire(); if (!file.exists()) return; IFileStore store = localManager.getStore(file); final IFileInfo fileInfo = store.fetchInfo(); if (!fileInfo.exists()) return; localManager.getHistoryStore().addState(file.getFullPath(), store, fileInfo, false); } finally { lock.release(); } } private IFileStore computeDestinationStore(IProjectDescription destDescription) throws CoreException { URI destLocation = destDescription.getLocationURI(); // Use the default area if necessary for the destination. if (destLocation == null) { IPath rootLocation = ResourcesPlugin.getWorkspace().getRoot().getLocation(); destLocation = rootLocation.append(destDescription.getName()).toFile().toURI(); } return EFS.getStore(destLocation); }
See Also:
  • computeTimestamp.computeTimestamp(IFile)
/** * @see IResourceTree#computeTimestamp(IFile) */
@Override public long computeTimestamp(IFile file) { Assert.isLegal(isValid); try { lock.acquire(); if (!file.getProject().exists()) return NULL_TIMESTAMP; return internalComputeTimestamp(file); } finally { lock.release(); } }
Copies the local history of source to destination. Note that if source is an IFolder, it is assumed that the same structure exists under destination and the local history of any IFile under source will be copied to the associated IFile under destination.
/** * Copies the local history of source to destination. Note that if source * is an IFolder, it is assumed that the same structure exists under destination * and the local history of any IFile under source will be copied to the * associated IFile under destination. */
private void copyLocalHistory(IResource source, IResource destination) { localManager.getHistoryStore().copyHistory(source, destination, true); }
See Also:
  • deletedFile.deletedFile(IFile)
/** * @see IResourceTree#deletedFile(IFile) */
@Override public void deletedFile(IFile file) { Assert.isLegal(isValid); try { lock.acquire(); // Do nothing if the resource doesn't exist. if (!file.exists()) return; try { // Delete properties, generate marker deltas, and remove the node from the workspace tree. ((Resource) file).deleteResource(true, null); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorDeleting, file.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, file.getFullPath(), message, e); failed(status); } } finally { lock.release(); } }
See Also:
  • deletedFolder.deletedFolder(IFolder)
/** * @see IResourceTree#deletedFolder(IFolder) */
@Override public void deletedFolder(IFolder folder) { Assert.isLegal(isValid); try { lock.acquire(); // Do nothing if the resource doesn't exist. if (!folder.exists()) return; try { // Delete properties, generate marker deltas, and remove the node from the workspace tree. ((Resource) folder).deleteResource(true, null); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorDeleting, folder.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, folder.getFullPath(), message, e); failed(status); } } finally { lock.release(); } }
See Also:
  • deletedProject.deletedProject(IProject)
/** * @see IResourceTree#deletedProject(IProject) */
@Override public void deletedProject(IProject target) { Assert.isLegal(isValid); try { lock.acquire(); // Do nothing if the resource doesn't exist. if (!target.exists()) return; // Delete properties, generate marker deltas, and remove the node from the workspace tree. try { ((Project) target).deleteResource(false, null); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorDeleting, target.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, target.getFullPath(), message, e); // log the status but don't return until we try and delete the rest of the project info failed(status); } } finally { lock.release(); } }
Makes sure that the destination directory for a project move is unoccupied. Returns true if successful, and false if the move should be aborted
/** * Makes sure that the destination directory for a project move is unoccupied. * Returns true if successful, and false if the move should be aborted */
private boolean ensureDestinationEmpty(IProject source, IFileStore destinationStore, IProgressMonitor monitor) throws CoreException { String message; //Make sure the destination location is unoccupied if (!destinationStore.fetchInfo().exists()) return true; //check for existing children if (destinationStore.childNames(EFS.NONE, Policy.subMonitorFor(monitor, 0)).length > 0) { //allow case rename to proceed if (((Resource) source).getStore().equals(destinationStore)) return true; //fail because the destination is occupied message = NLS.bind(Messages.localstore_resourceExists, destinationStore); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, null); failed(status); return false; } //delete the destination directory to allow for efficient renaming destinationStore.delete(EFS.NONE, Policy.subMonitorFor(monitor, 0)); return true; }
This operation has failed for the given reason. Add it to this resource tree's status.
/** * This operation has failed for the given reason. Add it to this * resource tree's status. */
@Override public void failed(IStatus reason) { Assert.isLegal(isValid); multistatus.add(reason); }
Returns the status object held onto by this resource tree.
/** * Returns the status object held onto by this resource tree. */
protected IStatus getStatus() { return multistatus; }
See Also:
  • getTimestamp.getTimestamp(IFile)
/** * @see IResourceTree#getTimestamp(IFile) */
@Override public long getTimestamp(IFile file) { Assert.isLegal(isValid); try { lock.acquire(); if (!file.exists()) return NULL_TIMESTAMP; ResourceInfo info = ((File) file).getResourceInfo(false, false); return info == null ? NULL_TIMESTAMP : info.getLocalSyncInfo(); } finally { lock.release(); } }
Returns the local timestamp for a file.
Params:
  • file –
Returns:The local file system timestamp
/** * Returns the local timestamp for a file. * * @param file * @return The local file system timestamp */
private long internalComputeTimestamp(IFile file) { IFileInfo fileInfo = localManager.getStore(file).fetchInfo(); return fileInfo.exists() ? fileInfo.getLastModified() : NULL_TIMESTAMP; }
Helper method for #standardDeleteFile. Returns a boolean indicating whether or not the delete was successful.
/** * Helper method for #standardDeleteFile. Returns a boolean indicating whether or * not the delete was successful. */
private boolean internalDeleteFile(IFile file, int flags, IProgressMonitor monitor) { try { String message = NLS.bind(Messages.resources_deleting, file.getFullPath()); monitor.beginTask(message, Policy.totalWork); Policy.checkCanceled(monitor); // Do nothing if the file doesn't exist in the workspace. if (!file.exists()) { // Indicate that the delete was successful. return true; } // Don't delete contents if this is a linked resource if (file.isLinked()) { deletedFile(file); return true; } // If the file doesn't exist on disk then signal to the workspace to delete the // file and return. IFileStore fileStore = localManager.getStore(file); boolean localExists = fileStore.fetchInfo().exists(); if (!localExists) { deletedFile(file); // Indicate that the delete was successful. return true; } boolean keepHistory = (flags & IResource.KEEP_HISTORY) != 0; boolean force = (flags & IResource.FORCE) != 0; // Add the file to the local history if requested by the user. if (keepHistory) addToLocalHistory(file); monitor.worked(Policy.totalWork / 4); // We want to fail if force is false and the file is not synchronized with the // local file system. if (!force) { boolean inSync = isSynchronized(file, IResource.DEPTH_ZERO); // only want to fail if the file still exists. if (!inSync && localExists) { message = NLS.bind(Messages.localstore_resourceIsOutOfSync, file.getFullPath()); IStatus status = new ResourceStatus(IResourceStatus.OUT_OF_SYNC_LOCAL, file.getFullPath(), message); failed(status); // Indicate that the delete was unsuccessful. return false; } } monitor.worked(Policy.totalWork / 4); // Try to delete the file from the file system. try { fileStore.delete(EFS.NONE, Policy.subMonitorFor(monitor, Policy.totalWork / 4)); // If the file was successfully deleted from the file system the // workspace tree should be updated accordingly. deletedFile(file); // Indicate that the delete was successful. return true; } catch (CoreException e) { message = NLS.bind(Messages.resources_couldnotDelete, fileStore.toString()); IStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, file.getFullPath(), message, e); failed(status); } // Indicate that the delete was unsuccessful. return false; } finally { monitor.done(); } }
Helper method for #standardDeleteFolder. Returns a boolean indicating whether or not the deletion of this folder was successful. Does a best effort delete of this resource and its children.
/** * Helper method for #standardDeleteFolder. Returns a boolean indicating * whether or not the deletion of this folder was successful. Does a best effort * delete of this resource and its children. */
private boolean internalDeleteFolder(IFolder folder, int flags, IProgressMonitor monitor) { String message = NLS.bind(Messages.resources_deleting, folder.getFullPath()); monitor.beginTask("", Policy.totalWork); //$NON-NLS-1$ monitor.subTask(message); Policy.checkCanceled(monitor); // Do nothing if the folder doesn't exist in the workspace. if (!folder.exists()) return true; // Don't delete contents if this is a linked resource if (folder.isLinked()) { deletedFolder(folder); return true; } // If the folder doesn't exist on disk then update the tree and return. IFileStore fileStore = localManager.getStore(folder); if (!fileStore.fetchInfo().exists()) { deletedFolder(folder); return true; } try { //this will delete local and workspace localManager.delete(folder, flags, Policy.subMonitorFor(monitor, Policy.totalWork)); } catch (CoreException ce) { message = NLS.bind(Messages.localstore_couldnotDelete, folder.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, IResourceStatus.FAILED_DELETE_LOCAL, folder.getFullPath(), message, ce); failed(status); return false; } return true; }
Does a best-effort delete on this resource and all its children.
/** * Does a best-effort delete on this resource and all its children. */
private boolean internalDeleteProject(IProject project, int flags, IProgressMonitor monitor) { // Recursively delete each member of the project. IResource[] members = null; try { members = project.members(IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorMembers, project.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, project.getFullPath(), message, e); failed(status); // Indicate that the delete was unsuccessful. return false; } boolean deletedChildren = true; for (IResource member : members) { IResource child = member; switch (child.getType()) { case IResource.FILE : // ignore the .project file for now and delete it last if (!IProjectDescription.DESCRIPTION_FILE_NAME.equals(child.getName())) deletedChildren &= internalDeleteFile((IFile) child, flags, Policy.subMonitorFor(monitor, Policy.totalWork / members.length)); break; case IResource.FOLDER : deletedChildren &= internalDeleteFolder((IFolder) child, flags, Policy.subMonitorFor(monitor, Policy.totalWork / members.length)); break; } } IFileStore projectStore = localManager.getStore(project); // Check to see if the children were deleted ok. If there was a problem // just return as the problem should have been logged by the recursive // call to the child. if (!deletedChildren) // Indicate that the delete was unsuccessful. return false; //Check if there are any undiscovered children of the project on disk other than description file String[] children; try { children = projectStore.childNames(EFS.NONE, null); } catch (CoreException e) { //treat failure to access the directory as a non-existent directory children = new String[0]; } boolean force = BitMask.isSet(flags, IResource.FORCE); if (!force && (children.length != 1 || !IProjectDescription.DESCRIPTION_FILE_NAME.equals(children[0]))) { String message = NLS.bind(Messages.localstore_resourceIsOutOfSync, project.getName()); failed(new ResourceStatus(IResourceStatus.OUT_OF_SYNC_LOCAL, project.getFullPath(), message)); return false; } //Now delete the project description file IResource file = project.findMember(IProjectDescription.DESCRIPTION_FILE_NAME); if (file == null) { //the .project have may have been recreated on disk automatically by snapshot IFileStore dotProject = projectStore.getChild(IProjectDescription.DESCRIPTION_FILE_NAME); try { dotProject.delete(EFS.NONE, null); } catch (CoreException e) { failed(e.getStatus()); } } else { boolean deletedProjectFile = internalDeleteFile((IFile) file, flags, Policy.monitorFor(null)); if (!deletedProjectFile) { String message = NLS.bind(Messages.resources_couldnotDelete, file.getFullPath()); IStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, file.getFullPath(), message); failed(status); // Indicate that the delete was unsuccessful. return false; } } //children are deleted, so now delete the parent try { projectStore.delete(EFS.NONE, null); deletedProject(project); // Indicate that the delete was successful. return true; } catch (CoreException e) { String message = NLS.bind(Messages.resources_couldnotDelete, projectStore.toString()); IStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, project.getFullPath(), message, e); failed(status); // Indicate that the delete was unsuccessful. return false; } }
Return true if there is a change in the content area for the project.
/** * Return <code>true</code> if there is a change in the content area for the project. */
private boolean isContentChange(IProject project, IProjectDescription destDescription) { IProjectDescription srcDescription = ((Project) project).internalGetDescription(); URI srcLocation = srcDescription.getLocationURI(); URI destLocation = destDescription.getLocationURI(); if (srcLocation == null || destLocation == null) return true; //don't use URIUtil because we want to treat case rename as a content change return !srcLocation.equals(destLocation); }
Return true if there is a change in the name of the project.
/** * Return <code>true</code> if there is a change in the name of the project. */
private boolean isNameChange(IProject project, IProjectDescription description) { return !project.getName().equals(description.getName()); }
Refreshes the resource hierarchy with its children. In case of failure adds an appropriate status to the resource tree's status.
/** * Refreshes the resource hierarchy with its children. In case of failure * adds an appropriate status to the resource tree's status. */
private void safeRefresh(IResource resource) { try { resource.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); } catch (CoreException ce) { IStatus status = new ResourceStatus(IStatus.ERROR, IResourceStatus.FAILED_DELETE_LOCAL, resource.getFullPath(), Messages.refresh_refreshErr, ce); failed(status); } }
See Also:
  • isSynchronized.isSynchronized(IResource, int)
/** * @see IResourceTree#isSynchronized(IResource, int) */
@Override public boolean isSynchronized(IResource resource, int depth) { try { lock.acquire(); return localManager.isSynchronized(resource, depth); } finally { lock.release(); } }
The specific operation for which this tree was created has completed and this tree should not be used anymore. Ensure that this is the case by making it invalid. This is checked by all API methods.
/** * The specific operation for which this tree was created has completed and this tree * should not be used anymore. Ensure that this is the case by making it invalid. This * is checked by all API methods. */
void makeInvalid() { this.isValid = false; }
See Also:
  • movedFile.movedFile(IFile, IFile)
/** * @see IResourceTree#movedFile(IFile, IFile) */
@Override public void movedFile(IFile source, IFile destination) { Assert.isLegal(isValid); try { lock.acquire(); // Do nothing if the resource doesn't exist. if (!source.exists()) return; // If the destination already exists then we have a problem. if (destination.exists()) { String message = NLS.bind(Messages.resources_mustNotExist, destination.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, destination.getFullPath(), message); // log the status but don't return until we try and move the rest of the resource information. failed(status); } // Move the resource's persistent properties. IPropertyManager propertyManager = ((Resource) source).getPropertyManager(); try { propertyManager.copy(source, destination, IResource.DEPTH_ZERO); propertyManager.deleteProperties(source, IResource.DEPTH_ZERO); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorPropertiesMove, source.getFullPath(), destination.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); // log the status but don't return until we try and move the rest of the resource information. failed(status); } // Move the node in the workspace tree. Workspace workspace = (Workspace) source.getWorkspace(); try { workspace.move((Resource) source, destination.getFullPath(), IResource.DEPTH_ZERO, updateFlags, false); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorMoving, source.getFullPath(), destination.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); // log the status but don't return until we try and move the rest of the resource information. failed(status); } // Generate the marker deltas. try { workspace.getMarkerManager().moved(source, destination, IResource.DEPTH_ZERO); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorMarkersDelete, source.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); failed(status); } // Copy the local history information copyLocalHistory(source, destination); } finally { lock.release(); } }
See Also:
  • movedFolderSubtree.movedFolderSubtree(IFolder, IFolder)
/** * @see IResourceTree#movedFolderSubtree(IFolder, IFolder) */
@Override public void movedFolderSubtree(IFolder source, IFolder destination) { Assert.isLegal(isValid); try { lock.acquire(); // Do nothing if the source resource doesn't exist. if (!source.exists()) return; // If the destination already exists then we have an error. if (destination.exists()) { String message = NLS.bind(Messages.resources_mustNotExist, destination.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, destination.getFullPath(), message); failed(status); return; } // Move the folder properties. int depth = IResource.DEPTH_INFINITE; IPropertyManager propertyManager = ((Resource) source).getPropertyManager(); try { propertyManager.copy(source, destination, depth); propertyManager.deleteProperties(source, depth); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorPropertiesMove, source.getFullPath(), destination.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); // log the status but don't return until we try and move the rest of the resource info failed(status); } // Create the destination node in the tree. Workspace workspace = (Workspace) source.getWorkspace(); try { workspace.move((Resource) source, destination.getFullPath(), depth, updateFlags, false); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorMoving, source.getFullPath(), destination.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); // log the status but don't return until we try and move the rest of the resource info failed(status); } // Generate the marker deltas. try { workspace.getMarkerManager().moved(source, destination, depth); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorMarkersDelete, source.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); failed(status); } // Copy the local history for this folder copyLocalHistory(source, destination); } finally { lock.release(); } }
See Also:
  • movedProjectSubtree.movedProjectSubtree(IProject, IProjectDescription)
/** * @see IResourceTree#movedProjectSubtree(IProject, IProjectDescription) */
@Override public boolean movedProjectSubtree(IProject project, IProjectDescription destDescription) { Assert.isLegal(isValid); try { lock.acquire(); // Do nothing if the source resource doesn't exist. if (!project.exists()) return true; Project source = (Project) project; Project destination = (Project) source.getWorkspace().getRoot().getProject(destDescription.getName()); Workspace workspace = (Workspace) source.getWorkspace(); int depth = IResource.DEPTH_INFINITE; // If the name of the source and destination projects are not the same then // rename the meta area and make changes in the tree. if (isNameChange(source, destDescription)) { if (destination.exists()) { String message = NLS.bind(Messages.resources_mustNotExist, destination.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, destination.getFullPath(), message); failed(status); return false; } // Rename the project metadata area. Close the property store to flush everything to disk try { source.getPropertyManager().closePropertyStore(source); localManager.getHistoryStore().closeHistoryStore(source); } catch (CoreException e) { String message = NLS.bind(Messages.properties_couldNotClose, source.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); // log the status but don't return until we try and move the rest of the resource info failed(status); } final IFileSystem fileSystem = EFS.getLocalFileSystem(); IFileStore oldMetaArea = fileSystem.getStore(workspace.getMetaArea().locationFor(source)); IFileStore newMetaArea = fileSystem.getStore(workspace.getMetaArea().locationFor(destination)); try { oldMetaArea.move(newMetaArea, EFS.NONE, new NullProgressMonitor()); } catch (CoreException e) { String message = NLS.bind(Messages.resources_moveMeta, oldMetaArea, newMetaArea); IStatus status = new ResourceStatus(IResourceStatus.FAILED_WRITE_METADATA, destination.getFullPath(), message, e); // log the status but don't return until we try and move the rest of the resource info failed(status); } // Move the workspace tree. try { workspace.move(source, destination.getFullPath(), depth, updateFlags, true); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorMoving, source.getFullPath(), destination.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); // log the status but don't return until we try and move the rest of the resource info failed(status); } // Clear stale state on the destination project. ((ProjectInfo) destination.getResourceInfo(false, true)).fixupAfterMove(); // Generate marker deltas. try { workspace.getMarkerManager().moved(source, destination, depth); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorMarkersMove, source.getFullPath(), destination.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); // log the status but don't return until we try and move the rest of the resource info failed(status); } // Copy the local history copyLocalHistory(source, destination); } // Write the new project description on the destination project. try { //moving linked resources may have modified the description in memory ((ProjectDescription) destDescription).setLinkDescriptions(destination.internalGetDescription().getLinks()); // moving filters may have modified the description in memory ((ProjectDescription) destDescription).setFilterDescriptions(destination.internalGetDescription().getFilters()); // moving variables may have modified the description in memory ((ProjectDescription) destDescription).setVariableDescriptions(destination.internalGetDescription().getVariables()); destination.internalSetDescription(destDescription, true); destination.writeDescription(IResource.FORCE); } catch (CoreException e) { String message = Messages.resources_projectDesc; IStatus status = new ResourceStatus(IStatus.ERROR, destination.getFullPath(), message, e); failed(status); } // write the private project description, including the project location try { workspace.getMetaArea().writePrivateDescription(destination); } catch (CoreException e) { failed(e.getStatus()); } // Do a refresh on the destination project to pick up any newly discovered resources try { destination.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); } catch (CoreException e) { String message = NLS.bind(Messages.resources_errorRefresh, destination.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, destination.getFullPath(), message, e); failed(status); return false; } return true; } finally { lock.release(); } }
Helper method for moving the project content. Determines the content location based on the project description. (default location or user defined?)
/** * Helper method for moving the project content. Determines the content location * based on the project description. (default location or user defined?) */
private void moveProjectContent(IProject source, IFileStore destStore, int flags, IProgressMonitor monitor) throws CoreException { try { String message = NLS.bind(Messages.resources_moving, source.getFullPath()); monitor.beginTask(message, 10); IProjectDescription srcDescription = source.getDescription(); URI srcLocation = srcDescription.getLocationURI(); // If the locations are the same (and non-default) then there is nothing to do. if (srcLocation != null && URIUtil.equals(srcLocation, destStore.toURI())) return; //If this is a replace, just make sure the destination location exists, and return boolean replace = (flags & IResource.REPLACE) != 0; if (replace) { destStore.mkdir(EFS.NONE, Policy.subMonitorFor(monitor, 10)); return; } // Move the contents on disk. localManager.move(source, destStore, flags, Policy.subMonitorFor(monitor, 9)); //if this is a deep move, move the contents of any linked resources if ((flags & IResource.SHALLOW) == 0) { IResource[] children = source.members(); for (IResource element : children) { if (element.isLinked()) { message = NLS.bind(Messages.resources_moving, element.getFullPath()); monitor.subTask(message); IFileStore linkDestination = destStore.getChild(element.getName()); try { localManager.move(element, linkDestination, flags, Policy.monitorFor(null)); } catch (CoreException ce) { //log the failure, but keep trying on remaining links failed(ce.getStatus()); } } } } monitor.worked(1); } finally { monitor.done(); } }
See Also:
  • standardDeleteFile.standardDeleteFile(IFile, int, IProgressMonitor)
/** * @see IResourceTree#standardDeleteFile(IFile, int, IProgressMonitor) */
@Override public void standardDeleteFile(IFile file, int flags, IProgressMonitor monitor) { Assert.isLegal(isValid); try { lock.acquire(); internalDeleteFile(file, flags, monitor); } finally { lock.release(); } }
See Also:
  • standardDeleteFolder.standardDeleteFolder(IFolder, int, IProgressMonitor)
/** * @see IResourceTree#standardDeleteFolder(IFolder, int, IProgressMonitor) */
@Override public void standardDeleteFolder(IFolder folder, int flags, IProgressMonitor monitor) { Assert.isLegal(isValid); try { lock.acquire(); internalDeleteFolder(folder, flags, monitor); } catch (OperationCanceledException oce) { safeRefresh(folder); throw oce; } finally { lock.release(); monitor.done(); } }
See Also:
  • standardDeleteProject.standardDeleteProject(IProject, int, IProgressMonitor)
/** * @see IResourceTree#standardDeleteProject(IProject, int, IProgressMonitor) */
@Override public void standardDeleteProject(IProject project, int flags, IProgressMonitor monitor) { Assert.isLegal(isValid); try { lock.acquire(); String message = NLS.bind(Messages.resources_deleting, project.getFullPath()); monitor.beginTask(message, Policy.totalWork); // Do nothing if the project doesn't exist in the workspace tree. if (!project.exists()) return; boolean alwaysDeleteContent = (flags & IResource.ALWAYS_DELETE_PROJECT_CONTENT) != 0; boolean neverDeleteContent = (flags & IResource.NEVER_DELETE_PROJECT_CONTENT) != 0; boolean success = true; // Delete project content. Don't do anything if the user specified explicitly asked // not to delete the project content or if the project is closed and // ALWAYS_DELETE_PROJECT_CONTENT was not specified. if (alwaysDeleteContent || (project.isOpen() && !neverDeleteContent)) { // Force is implied if alwaysDeleteContent is true or if the project is in sync // with the local file system. if (alwaysDeleteContent || isSynchronized(project, IResource.DEPTH_INFINITE)) { flags |= IResource.FORCE; } // If the project is open we have to recursively try and delete all the files doing best-effort. if (project.isOpen()) { success = internalDeleteProject(project, flags, monitor); if (!success) { IFileStore store = localManager.getStore(project); message = NLS.bind(Messages.resources_couldnotDelete, store.toString()); IStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, project.getFullPath(), message); failed(status); } return; } // If the project is closed we can short circuit this operation and delete all the files on disk. // The .project file is deleted at the end of the operation. try { IFileStore projectStore = localManager.getStore(project); IFileStore members[] = projectStore.childStores(EFS.NONE, null); for (IFileStore member : members) { if (!IProjectDescription.DESCRIPTION_FILE_NAME.equals(member.getName())) { member.delete(EFS.NONE, Policy.subMonitorFor(monitor, Policy.totalWork * 7 / 8 / members.length)); } } projectStore.delete(EFS.NONE, Policy.subMonitorFor(monitor, Policy.totalWork * 7 / 8 / (members.length > 0 ? members.length : 1))); } catch (OperationCanceledException oce) { safeRefresh(project); throw oce; } catch (CoreException ce) { message = NLS.bind(Messages.localstore_couldnotDelete, project.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, IResourceStatus.FAILED_DELETE_LOCAL, project.getFullPath(), message, ce); failed(status); return; } } // Signal that the workspace tree should be updated that the project has been deleted. if (success) deletedProject(project); else { message = NLS.bind(Messages.localstore_couldnotDelete, project.getFullPath()); IStatus status = new ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, project.getFullPath(), message); failed(status); } } finally { lock.release(); monitor.done(); } }
See Also:
  • standardMoveFile.standardMoveFile(IFile, IFile, int, IProgressMonitor)
/** * @see IResourceTree#standardMoveFile(IFile, IFile, int, IProgressMonitor) */
@Override public void standardMoveFile(IFile source, IFile destination, int flags, IProgressMonitor monitor) { Assert.isLegal(isValid); try { lock.acquire(); String message = NLS.bind(Messages.resources_moving, source.getFullPath()); monitor.subTask(message); // These pre-conditions should all be ok but just in case... if (!source.exists() || destination.exists() || !destination.getParent().isAccessible()) throw new IllegalArgumentException(); boolean force = (flags & IResource.FORCE) != 0; boolean keepHistory = (flags & IResource.KEEP_HISTORY) != 0; boolean isDeep = (flags & IResource.SHALLOW) == 0; // If the file is not in sync with the local file system and force is false, // then signal that we have an error. if (!force && !isSynchronized(source, IResource.DEPTH_INFINITE)) { message = NLS.bind(Messages.localstore_resourceIsOutOfSync, source.getFullPath()); IStatus status = new ResourceStatus(IResourceStatus.OUT_OF_SYNC_LOCAL, source.getFullPath(), message); failed(status); return; } monitor.worked(Policy.totalWork / 4); // Add the file contents to the local history if requested by the user. if (keepHistory) addToLocalHistory(source); monitor.worked(Policy.totalWork / 4); //for shallow move of linked resources, nothing needs to be moved in the file system if (!isDeep && source.isLinked()) { movedFile(source, destination); return; } // If the file was successfully moved in the file system then the workspace // tree needs to be updated accordingly. Otherwise signal that we have an error. IFileStore destStore = null; boolean failedDeletingSource = false; try { destStore = localManager.getStore(destination); //ensure parent of destination exists destStore.getParent().mkdir(EFS.NONE, Policy.subMonitorFor(monitor, 0)); localManager.move(source, destStore, flags, monitor); } catch (CoreException e) { failed(e.getStatus()); // did the fail occur after copying to the destination? failedDeletingSource = destStore != null && destStore.fetchInfo().exists(); // if so, we should proceed if (!failedDeletingSource) return; } movedFile(source, destination); updateMovedFileTimestamp(destination, internalComputeTimestamp(destination)); if (failedDeletingSource) { //recreate source file to ensure we are not out of sync try { source.refreshLocal(IResource.DEPTH_INFINITE, null); } catch (CoreException e) { //ignore secondary failure - we have already logged the main failure } } monitor.worked(Policy.totalWork / 4); return; } finally { lock.release(); monitor.done(); } }
See Also:
  • standardMoveFolder.standardMoveFolder(IFolder, IFolder, int, IProgressMonitor)
/** * @see IResourceTree#standardMoveFolder(IFolder, IFolder, int, IProgressMonitor) */
@Override public void standardMoveFolder(IFolder source, IFolder destination, int flags, IProgressMonitor monitor) { Assert.isLegal(isValid); try { lock.acquire(); String message = NLS.bind(Messages.resources_moving, source.getFullPath()); monitor.beginTask(message, 100); // These pre-conditions should all be ok but just in case... if (!source.exists() || destination.exists() || !destination.getParent().isAccessible()) throw new IllegalArgumentException(); // Check to see if we are synchronized with the local file system. If we are in sync then we can // short circuit this method and do a file system only move. Otherwise we have to recursively // try and move all resources, doing it in a best-effort manner. boolean force = (flags & IResource.FORCE) != 0; if (!force && !isSynchronized(source, IResource.DEPTH_INFINITE)) { message = NLS.bind(Messages.localstore_resourceIsOutOfSync, source.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message); failed(status); return; } monitor.worked(20); //for linked resources, nothing needs to be moved in the file system boolean isDeep = (flags & IResource.SHALLOW) == 0; if (!isDeep && (source.isLinked() || source.isVirtual())) { movedFolderSubtree(source, destination); return; } // Move the resources in the file system. Only the FORCE flag is valid here so don't // have to worry about clearing the KEEP_HISTORY flag. IFileStore destStore = null; boolean failedDeletingSource = false; try { destStore = localManager.getStore(destination); localManager.move(source, destStore, flags, Policy.subMonitorFor(monitor, 60)); } catch (CoreException e) { failed(e.getStatus()); // did the fail occur after copying to the destination? failedDeletingSource = destStore != null && destStore.fetchInfo().exists(); // if so, we should proceed if (!failedDeletingSource) return; } movedFolderSubtree(source, destination); monitor.worked(20); updateTimestamps(destination, isDeep); if (failedDeletingSource) { //the move could have been partially successful, so refresh to ensure we are in sync try { source.refreshLocal(IResource.DEPTH_INFINITE, null); destination.refreshLocal(IResource.DEPTH_INFINITE, null); } catch (CoreException e) { //ignore secondary failures -we have already logged main failure } } } finally { lock.release(); monitor.done(); } }
See Also:
  • standardMoveProject.standardMoveProject(IProject, IProjectDescription, int, IProgressMonitor)
/** * @see IResourceTree#standardMoveProject(IProject, IProjectDescription, int, IProgressMonitor) */
@Override public void standardMoveProject(IProject source, IProjectDescription description, int flags, IProgressMonitor monitor) { Assert.isLegal(isValid); try { lock.acquire(); String message = NLS.bind(Messages.resources_moving, source.getFullPath()); monitor.beginTask(message, Policy.totalWork); // Double-check this pre-condition. if (!source.isAccessible()) throw new IllegalArgumentException(); // If there is nothing to do on disk then signal to make the workspace tree // changes. if (!isContentChange(source, description)) { movedProjectSubtree(source, description); return; } // Check to see if we are synchronized with the local file system. boolean force = (flags & IResource.FORCE) != 0; if (!force && !isSynchronized(source, IResource.DEPTH_INFINITE)) { // FIXME: make this a best effort move? message = NLS.bind(Messages.localstore_resourceIsOutOfSync, source.getFullPath()); IStatus status = new ResourceStatus(IResourceStatus.OUT_OF_SYNC_LOCAL, source.getFullPath(), message); failed(status); return; } IFileStore destinationStore; try { destinationStore = computeDestinationStore(description); //destination can be non-empty on replace if ((flags & IResource.REPLACE) == 0) if (!ensureDestinationEmpty(source, destinationStore, monitor)) return; } catch (CoreException e) { //must fail if the destination location cannot be accessd (undefined file system) message = NLS.bind(Messages.localstore_couldNotMove, source.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); failed(status); return; } // Move the project content in the local file system. try { moveProjectContent(source, destinationStore, flags, Policy.subMonitorFor(monitor, Policy.totalWork * 3 / 4)); } catch (CoreException e) { message = NLS.bind(Messages.localstore_couldNotMove, source.getFullPath()); IStatus status = new ResourceStatus(IStatus.ERROR, source.getFullPath(), message, e); failed(status); //refresh the project because it might have been partially moved try { source.refreshLocal(IResource.DEPTH_INFINITE, null); } catch (CoreException e2) { //ignore secondary failures } } // If we got this far the project content has been moved on disk (if necessary) // and we need to update the workspace tree. movedProjectSubtree(source, description); monitor.worked(Policy.totalWork * 1 / 8); boolean isDeep = (flags & IResource.SHALLOW) == 0; updateTimestamps(source.getWorkspace().getRoot().getProject(description.getName()), isDeep); monitor.worked(Policy.totalWork * 1 / 8); } finally { lock.release(); monitor.done(); } }
See Also:
  • updateMovedFileTimestamp.updateMovedFileTimestamp(IFile, long)
/** * @see IResourceTree#updateMovedFileTimestamp(IFile, long) */
@Override public void updateMovedFileTimestamp(IFile file, long timestamp) { Assert.isLegal(isValid); try { lock.acquire(); // Do nothing if the file doesn't exist in the workspace tree. if (!file.exists()) return; // Update the timestamp in the tree. ResourceInfo info = ((Resource) file).getResourceInfo(false, true); // The info should never be null since we just checked that the resource exists in the tree. localManager.updateLocalSync(info, timestamp); //remove the linked bit since this resource has been moved in the file system info.clear(ICoreConstants.M_LINK); } finally { lock.release(); } }
Helper method to update all the timestamps in the tree to match those in the file system. Used after a #move.
/** * Helper method to update all the timestamps in the tree to match * those in the file system. Used after a #move. */
private void updateTimestamps(IResource root, final boolean isDeep) { IResourceVisitor visitor = resource -> { if (resource.isLinked()) { if (isDeep && !((Resource) resource).isUnderVirtual()) { //clear the linked resource bit, if any ResourceInfo info = ((Resource) resource).getResourceInfo(false, true); info.clear(ICoreConstants.M_LINK); } return true; } //only needed if underlying file system does not preserve timestamps // if (resource.getType() == IResource.FILE) { // IFile file = (IFile) resource; // updateMovedFileTimestamp(file, computeTimestamp(file)); // } return true; }; try { root.accept(visitor, IResource.DEPTH_INFINITE, IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); } catch (CoreException e) { // No exception should be thrown. } } }