blob: e78e86ce3caea6f5306b43a49847ef65d6c41387 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.internal.core;
import org.eclipse.core.resources.IFolder;
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.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IBuildpathEntry;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.IModelStatus;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.IScriptModel;
import org.eclipse.dltk.core.ModelException;
public class MoveProjectFragmentOperation extends CopyProjectFragmentOperation {
/*
* Renames the buildpath entries equal to the given path in the given project.
* If an entry with the destination path already existed, remove it.
*/
protected void renameEntryInBuildpath(IPath rootPath, IScriptProject project) throws ModelException {
IBuildpathEntry[] buildpath = project.getRawBuildpath();
IBuildpathEntry[] newBuildpath = null;
int cpLength = buildpath.length;
int newCPIndex = -1;
for (int i = 0; i < cpLength; i++) {
IBuildpathEntry entry = buildpath[i];
IPath entryPath = entry.getPath();
if (rootPath.equals(entryPath)) {
// rename entry
if (newBuildpath == null) {
newBuildpath = new IBuildpathEntry[cpLength];
System.arraycopy(buildpath, 0, newBuildpath, 0, i);
newCPIndex = i;
}
newBuildpath[newCPIndex++] = copy(entry);
} else if (this.destination.equals(entryPath)) {
// remove entry equals to destination
if (newBuildpath == null) {
newBuildpath = new IBuildpathEntry[cpLength];
System.arraycopy(buildpath, 0, newBuildpath, 0, i);
newCPIndex = i;
}
} else if (entry.getEntryKind() == IBuildpathEntry.BPE_SOURCE) {
// update exclusion/inclusion patterns
IPath projectRelativePath = rootPath.removeFirstSegments(1);
IPath[] newExclusionPatterns = renamePatterns(projectRelativePath, entry.getExclusionPatterns());
IPath[] newInclusionPatterns = renamePatterns(projectRelativePath, entry.getInclusionPatterns());
if (newExclusionPatterns != null || newInclusionPatterns != null) {
if (newBuildpath == null) {
newBuildpath = new IBuildpathEntry[cpLength];
System.arraycopy(buildpath, 0, newBuildpath, 0, i);
newCPIndex = i;
}
newBuildpath[newCPIndex++] =
DLTKCore.newSourceEntry(
entry.getPath(),
newInclusionPatterns == null ? entry.getInclusionPatterns() : newInclusionPatterns,
newExclusionPatterns == null ? entry.getExclusionPatterns() : newExclusionPatterns,
entry.getExtraAttributes());
} else if (newBuildpath != null) {
newBuildpath[newCPIndex++] = entry;
}
} else if (newBuildpath != null) {
newBuildpath[newCPIndex++] = entry;
}
}
if (newBuildpath != null) {
if (newCPIndex < newBuildpath.length) {
System.arraycopy(newBuildpath, 0, newBuildpath = new IBuildpathEntry[newCPIndex], 0, newCPIndex);
}
IModelStatus status = BuildpathEntry.validateBuildpath(project, newBuildpath);
if (status.isOK())
project.setRawBuildpath(newBuildpath, progressMonitor);
// don't update buildpath if status is not ok to avoid ScriptModelException (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=129991)
}
}
private IPath[] renamePatterns(IPath rootPath, IPath[] patterns) {
IPath[] newPatterns = null;
int newPatternsIndex = -1;
for (int i = 0, length = patterns.length; i < length; i++) {
IPath pattern = patterns[i];
if (pattern.equals(rootPath)) {
if (newPatterns == null) {
newPatterns = new IPath[length];
System.arraycopy(patterns, 0, newPatterns, 0, i);
newPatternsIndex = i;
}
IPath newPattern = this.destination.removeFirstSegments(1);
if (pattern.hasTrailingSeparator())
newPattern = newPattern.addTrailingSeparator();
newPatterns[newPatternsIndex++] = newPattern;
}
}
return newPatterns;
}
public MoveProjectFragmentOperation(
IProjectFragment root,
IPath destination,
int updateResourceFlags,
int updateModelFlags,
IBuildpathEntry sibling) {
super(
root,
destination,
updateResourceFlags,
updateModelFlags,
sibling);
}
@Override
protected void executeOperation() throws ModelException {
IProjectFragment root = (IProjectFragment)this.getElementToProcess();
IBuildpathEntry rootEntry = root.getRawBuildpathEntry();
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
// move resource
if (!root.isExternal() && (this.updateModelFlags & IProjectFragment.NO_RESOURCE_MODIFICATION) == 0) {
moveResource(root, rootEntry, workspaceRoot);
}
// update refering projects buildpath excluding orignating project
IScriptProject originatingProject = root.getScriptProject();
if ((this.updateModelFlags & IProjectFragment.OTHER_REFERRING_PROJECTS_BUILDPATH) != 0) {
updateReferringProjectBuildpaths(rootEntry.getPath(), originatingProject);
}
boolean isRename = this.destination.segment(0).equals(originatingProject.getElementName());
boolean updateOriginating = (this.updateModelFlags & IProjectFragment.ORIGINATING_PROJECT_BUILDPATH) != 0;
boolean updateDestination = (this.updateModelFlags & IProjectFragment.DESTINATION_PROJECT_BUILDPATH) != 0;
// update originating buildpath
if (updateOriginating) {
if (isRename && updateDestination) {
renameEntryInBuildpath(rootEntry.getPath(), originatingProject);
} else {
removeEntryFromBuildpath(rootEntry.getPath(), originatingProject);
}
}
// update destination buildpath
if (updateDestination) {
if (!isRename || !updateOriginating) {
addEntryToBuildpath(rootEntry, workspaceRoot);
} // else reference has been updated when updating originating project buildpath
}
}
protected void moveResource(
IProjectFragment root,
IBuildpathEntry rootEntry,
final IWorkspaceRoot workspaceRoot)
throws ModelException {
final char[][] exclusionPatterns = ((BuildpathEntry)rootEntry).fullExclusionPatternChars();
IResource rootResource = root.getResource();
if (rootEntry.getEntryKind() != IBuildpathEntry.BPE_SOURCE || exclusionPatterns == null) {
try {
IResource destRes;
if ((this.updateModelFlags & IProjectFragment.REPLACE) != 0
&& (destRes = workspaceRoot.findMember(this.destination)) != null) {
destRes.delete(this.updateResourceFlags, progressMonitor);
}
rootResource.move(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().move(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().move(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);
}
/*
* Renames the buildpath entries equal to the given path in all Script projects.
*/
protected void updateReferringProjectBuildpaths(IPath rootPath, IScriptProject projectOfRoot) throws ModelException {
IScriptModel model = this.getModel();
IScriptProject[] projects = model.getScriptProjects();
for (int i = 0, length = projects.length; i < length; i++) {
IScriptProject project = projects[i];
if (project.equals(projectOfRoot)) continue;
renameEntryInBuildpath(rootPath, project);
}
}
/*
* Removes the buildpath entry equal to the given path from the given project's buildpath.
*/
protected void removeEntryFromBuildpath(IPath rootPath, IScriptProject project) throws ModelException {
IBuildpathEntry[] buildpath = project.getRawBuildpath();
IBuildpathEntry[] newBuildpath = null;
int cpLength = buildpath.length;
int newCPIndex = -1;
for (int i = 0; i < cpLength; i++) {
IBuildpathEntry entry = buildpath[i];
if (rootPath.equals(entry.getPath())) {
if (newBuildpath == null) {
newBuildpath = new IBuildpathEntry[cpLength];
System.arraycopy(buildpath, 0, newBuildpath, 0, i);
newCPIndex = i;
}
} else if (newBuildpath != null) {
newBuildpath[newCPIndex++] = entry;
}
}
if (newBuildpath != null) {
if (newCPIndex < newBuildpath.length) {
System.arraycopy(newBuildpath, 0, newBuildpath = new IBuildpathEntry[newCPIndex], 0, newCPIndex);
}
project.setRawBuildpath(newBuildpath, progressMonitor);
}
}
}