/******************************************************************************* * Copyright (c) 2000, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * *******************************************************************************/ package org.eclipse.dltk.internal.core; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceProxy; import org.eclipse.core.resources.IResourceProxyVisitor; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.AssertionFailedException; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.DLTKLanguageManager; import org.eclipse.dltk.core.IBuildpathEntry; import org.eclipse.dltk.core.IModelStatus; import org.eclipse.dltk.core.IModelStatusConstants; import org.eclipse.dltk.core.IProjectFragment; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.internal.core.util.Messages; public class CopyProjectFragmentOperation extends ModelOperation { IPath destination; int updateResourceFlags; int updateModelFlags; IBuildpathEntry sibling; public CopyProjectFragmentOperation(IProjectFragment root, IPath destination, int updateResourceFlags, int updateModelFlags, IBuildpathEntry sibling) { super(root); this.destination = destination; this.updateResourceFlags = updateResourceFlags; this.updateModelFlags = updateModelFlags; this.sibling = sibling; } @Override protected void executeOperation() throws ModelException { IProjectFragment root = (IProjectFragment) this.getElementToProcess(); IBuildpathEntry rootEntry = root.getRawBuildpathEntry(); IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); // copy resource if (!root.isExternal() && (this.updateModelFlags & IProjectFragment.NO_RESOURCE_MODIFICATION) == 0) { copyResource(root, rootEntry, workspaceRoot); } // update buildpath if needed if ((this.updateModelFlags & IProjectFragment.DESTINATION_PROJECT_BUILDPATH) != 0) { addEntryToBuildpath(rootEntry, workspaceRoot); } } protected void copyResource(IProjectFragment root, IBuildpathEntry rootEntry, final IWorkspaceRoot workspaceRoot) throws ModelException { final char[][] exclusionPatterns = ((BuildpathEntry) rootEntry) .fullExclusionPatternChars(); IResource rootResource = root.getResource(); if (root.getKind() == IProjectFragment.K_BINARY || exclusionPatterns == null) { try { IResource destRes; if ((this.updateModelFlags & IProjectFragment.REPLACE) != 0) { if (rootEntry.getPath().equals(this.destination)) return; if ((destRes = workspaceRoot.findMember(this.destination)) != null) { destRes.delete(this.updateResourceFlags, progressMonitor); } } rootResource.copy(this.destination, this.updateResourceFlags, progressMonitor); } catch (CoreException e) { throw new ModelException(e); } } else { final int sourceSegmentCount = rootEntry.getPath().segmentCount(); final IFolder destFolder = workspaceRoot .getFolder(this.destination); final IPath[] nestedFolders = getNestedFolders(root); IResourceProxyVisitor visitor = new IResourceProxyVisitor() { @Override public boolean visit(IResourceProxy proxy) throws CoreException { if (proxy.getType() == IResource.FOLDER) { IPath path = proxy.requestFullPath(); if (prefixesOneOf(path, nestedFolders)) { if (equalsOneOf(path, nestedFolders)) { // nested source folder return false; } else { // folder containing nested source folder IFolder folder = destFolder .getFolder(path .removeFirstSegments(sourceSegmentCount)); if ((updateModelFlags & IProjectFragment.REPLACE) != 0 && folder.exists()) { return true; } folder.create(updateResourceFlags, true, progressMonitor); return true; } } else { // subtree doesn't contain any nested source folders IPath destPath = destination.append(path .removeFirstSegments(sourceSegmentCount)); IResource destRes; if ((updateModelFlags & IProjectFragment.REPLACE) != 0 && (destRes = workspaceRoot .findMember(destPath)) != null) { destRes.delete(updateResourceFlags, progressMonitor); } proxy.requestResource().copy(destPath, updateResourceFlags, progressMonitor); return false; } } else { IPath path = proxy.requestFullPath(); IPath destPath = destination.append(path .removeFirstSegments(sourceSegmentCount)); IResource destRes; if ((updateModelFlags & IProjectFragment.REPLACE) != 0 && (destRes = workspaceRoot .findMember(destPath)) != null) { destRes .delete(updateResourceFlags, progressMonitor); } proxy.requestResource().copy(destPath, updateResourceFlags, progressMonitor); return false; } } }; try { rootResource.accept(visitor, IResource.NONE); } catch (CoreException e) { throw new ModelException(e); } } this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); } protected void addEntryToBuildpath(IBuildpathEntry rootEntry, IWorkspaceRoot workspaceRoot) throws ModelException { IProject destProject = workspaceRoot.getProject(this.destination .segment(0)); IScriptProject jProject = DLTKCore.create(destProject); IBuildpathEntry[] buildpath = jProject.getRawBuildpath(); int length = buildpath.length; IBuildpathEntry[] newBuildpath; // case of existing entry and REPLACE was specified if ((this.updateModelFlags & IProjectFragment.REPLACE) != 0) { // find existing entry for (int i = 0; i < length; i++) { if (this.destination.equals(buildpath[i].getPath())) { newBuildpath = new IBuildpathEntry[length]; System.arraycopy(buildpath, 0, newBuildpath, 0, length); newBuildpath[i] = copy(rootEntry); jProject.setRawBuildpath(newBuildpath, progressMonitor); return; } } } // other cases int position; if (this.sibling == null) { // insert at the end position = length; } else { // insert before sibling position = -1; for (int i = 0; i < length; i++) { if (this.sibling.equals(buildpath[i])) { position = i; break; } } } if (position == -1) { throw new ModelException(new ModelStatus( IModelStatusConstants.INVALID_SIBLING, this.sibling .toString())); } newBuildpath = new IBuildpathEntry[length + 1]; if (position != 0) { System.arraycopy(buildpath, 0, newBuildpath, 0, position); } if (position != length) { System.arraycopy(buildpath, position, newBuildpath, position + 1, length - position); } IBuildpathEntry newEntry = copy(rootEntry); newBuildpath[position] = newEntry; jProject.setRawBuildpath(newBuildpath, progressMonitor); } /* * Copies the given buildpath entry replacing its path with the destination * path if it is a source folder or a library. */ protected IBuildpathEntry copy(IBuildpathEntry entry) throws ModelException { switch (entry.getEntryKind()) { case IBuildpathEntry.BPE_CONTAINER: return DLTKCore.newContainerEntry(entry.getPath(), entry .getAccessRules(), entry.getExtraAttributes(), entry .isExported()); case IBuildpathEntry.BPE_LIBRARY: try { return DLTKCore.newLibraryEntry(this.destination, entry .getAccessRules(), entry.getExtraAttributes(), entry .isExported(), entry.isExternal()); } catch (AssertionFailedException e) { IModelStatus status = new ModelStatus( IModelStatusConstants.INVALID_PATH, e.getMessage()); throw new ModelException(status); } case IBuildpathEntry.BPE_PROJECT: return DLTKCore.newProjectEntry(entry.getPath(), entry .getAccessRules(), entry.combineAccessRules(), entry .getExtraAttributes(), entry.isExported()); case IBuildpathEntry.BPE_SOURCE: return DLTKCore.newSourceEntry(this.destination, entry .getInclusionPatterns(), entry.getExclusionPatterns(), entry.getExtraAttributes()); default: throw new ModelException(new ModelStatus( IModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this .getElementToProcess())); } } @Override public IModelStatus verify() { IModelStatus status = super.verify(); if (!status.isOK()) { return status; } IProjectFragment root = (IProjectFragment) getElementToProcess(); if (root == null || !root.exists()) { return new ModelStatus( IModelStatusConstants.ELEMENT_DOES_NOT_EXIST, root); } IResource resource = root.getResource(); if (resource instanceof IFolder) { if (resource.isLinked()) { return new ModelStatus(IModelStatusConstants.INVALID_RESOURCE, root); } } if ((this.updateModelFlags & IProjectFragment.DESTINATION_PROJECT_BUILDPATH) != 0) { String destProjectName = this.destination.segment(0); IProject project = ResourcesPlugin.getWorkspace().getRoot() .getProject(destProjectName); if (DLTKLanguageManager.hasScriptNature(project)) { try { IScriptProject destProject = DLTKCore.create(project); IBuildpathEntry[] destBuildpath = destProject .getRawBuildpath(); boolean foundSibling = false; boolean foundExistingEntry = false; for (int i = 0, length = destBuildpath.length; i < length; i++) { IBuildpathEntry entry = destBuildpath[i]; if (entry.equals(this.sibling)) { foundSibling = true; break; } if (entry.getPath().equals(this.destination)) { foundExistingEntry = true; } } if (this.sibling != null && !foundSibling) { return new ModelStatus( IModelStatusConstants.INVALID_SIBLING, this.sibling.toString()); } if (foundExistingEntry && (this.updateModelFlags & IProjectFragment.REPLACE) == 0) { return new ModelStatus( IModelStatusConstants.NAME_COLLISION, Messages .bind(Messages.status_nameCollision, new String[] { this.destination .toString() })); } } catch (ModelException e) { return e.getModelStatus(); } } } return ModelStatus.VERIFIED_OK; } }