blob: d5f6877d2852a2955ab8963ced99035747d01cb9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.dltk.internal.core;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.dltk.annotations.Nullable;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IBuildpathEntry;
import org.eclipse.dltk.core.IScriptProjectFilenames;
import org.eclipse.dltk.core.environment.EnvironmentPathUtils;
import org.eclipse.dltk.internal.core.util.Util;
public class ExternalFoldersManager {
private static final String EXTERNAL_PROJECT_NAME = ".org.eclipse.dltk.core.external.folders"; //$NON-NLS-1$
private static final String LINKED_FOLDER_NAME = ".link"; //$NON-NLS-1$
private HashMap folders;
private int counter = 0;
/*
* Returns a set of external path to external folders referred to on the
* given buildpath. Returns null if none.
*/
@Nullable
public static HashSet<IPath> getExternalFolders(
IBuildpathEntry[] buildpath) {
if (buildpath == null)
return null;
HashSet<IPath> folders = null;
for (int i = 0; i < buildpath.length; i++) {
IBuildpathEntry entry = buildpath[i];
if (entry.getEntryKind() == IBuildpathEntry.BPE_LIBRARY) {
IPath entryPath = entry.getPath();
if (EnvironmentPathUtils.isLocalEnvironment(entryPath)) {
final IPath local = EnvironmentPathUtils
.getLocalPath(entryPath);
if (isExternalFolderPath(local)) {
if (folders == null)
folders = new HashSet<>();
folders.add(local);
}
}
}
}
return folders;
}
public static boolean isExternalFolderPath(IPath externalPath) {
if (externalPath == null)
return false;
if (externalPath.segmentCount() > 0 && ResourcesPlugin.getWorkspace()
.getRoot().getProject(externalPath.segment(0)).exists())
return false;
File externalFolder = externalPath.toFile();
if (externalFolder.isFile())
return false;
if (externalPath.getFileExtension() != null/*
* likely a .jar, .zip, .rar
* or other file
*/
&& !externalFolder.exists())
return false;
return true;
}
public static boolean isInternalPathForExternalFolder(IPath resourcePath) {
return EXTERNAL_PROJECT_NAME.equals(resourcePath.segment(0));
}
public IFolder addFolder(IPath externalFolderPath) {
return addFolder(externalFolderPath, getExternalFoldersProject());
}
public IFolder addFolder(IPath externalFolderPath,
boolean scheduleForCreation) {
// TODO (alex) port not completed - scheduleForCreation not used
return addFolder(externalFolderPath, getExternalFoldersProject());
}
private synchronized IFolder addFolder(IPath externalFolderPath,
IProject externalFoldersProject) {
HashMap knownFolders = getFolders();
Object existing = knownFolders.get(externalFolderPath);
if (existing != null) {
return (IFolder) existing;
}
IFolder result;
do {
result = externalFoldersProject
.getFolder(LINKED_FOLDER_NAME + this.counter++);
} while (result.exists());
knownFolders.put(externalFolderPath, result);
return result;
}
public IFolder createLinkFolder(IPath externalFolderPath,
boolean refreshIfExistAlready, IProgressMonitor monitor)
throws CoreException {
IProject externalFoldersProject = createExternalFoldersProject(monitor); // run
// outside
// synchronized
// as
// this
// can
// create
// a
// resource
IFolder result = addFolder(externalFolderPath, externalFoldersProject);
if (!result.exists())
result.createLink(externalFolderPath, IResource.ALLOW_MISSING_LOCAL,
monitor);
else if (refreshIfExistAlready)
result.refreshLocal(IResource.DEPTH_INFINITE, monitor);
return result;
}
public synchronized void cleanUp(IProgressMonitor monitor)
throws CoreException {
DeltaProcessingState state = ModelManager.getModelManager().deltaState;
HashMap roots = state.roots;
// HashMap sourceAttachments = state.sourceAttachments;
if (roots == null /* && sourceAttachments == null */)
return;
HashMap knownFolders = getFolders();
Iterator iterator = knownFolders.keySet().iterator();
while (iterator.hasNext()) {
IPath path = (IPath) iterator.next();
if ((roots != null && !roots.containsKey(path))
/*
* & (sourceAttachments != null && !sourceAttachments
* .containsKey(path))
*/) {
IFolder folder = (IFolder) knownFolders.get(path);
if (folder != null)
folder.delete(true, monitor);
}
}
IProject project = getExternalFoldersProject();
if (project.isAccessible()
&& project.members().length == 1/*
* remaining member is .project
*/)
project.delete(true, monitor);
}
public IProject getExternalFoldersProject() {
return ResourcesPlugin.getWorkspace().getRoot()
.getProject(EXTERNAL_PROJECT_NAME);
}
private IProject createExternalFoldersProject(IProgressMonitor monitor) {
IProject project = getExternalFoldersProject();
if (!project.isAccessible()) {
try {
if (!project.exists()) {
IProjectDescription desc = project.getWorkspace()
.newProjectDescription(project.getName());
IPath stateLocation = DLTKCore.getPlugin()
.getStateLocation();
desc.setLocation(
stateLocation.append(EXTERNAL_PROJECT_NAME));
project.create(desc, IResource.HIDDEN, monitor);
}
try {
project.open(monitor);
} catch (CoreException e1) {
// .project or folder on disk have been deleted, recreate
// them
IPath stateLocation = DLTKCore.getPlugin()
.getStateLocation();
IPath projectPath = stateLocation
.append(EXTERNAL_PROJECT_NAME);
projectPath.toFile().mkdirs();
FileOutputStream output = new FileOutputStream(projectPath
.append(IScriptProjectFilenames.PROJECT_FILENAME)
.toOSString());
try {
output.write(
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" //$NON-NLS-1$
+ "<projectDescription>\n" + " <name>" //$NON-NLS-2$
+ EXTERNAL_PROJECT_NAME + "</name>\n" + //$NON-NLS-1$
" <comment></comment>\n" + //$NON-NLS-1$
" <projects>\n" + //$NON-NLS-1$
" </projects>\n" + //$NON-NLS-1$
" <buildSpec>\n" + //$NON-NLS-1$
" </buildSpec>\n" + //$NON-NLS-1$
" <natures>\n" + //$NON-NLS-1$
" </natures>\n" + //$NON-NLS-1$
"</projectDescription>").getBytes()); //$NON-NLS-1$
} finally {
output.close();
}
project.open(null);
}
} catch (CoreException e) {
Util.log(e,
"Problem creating hidden project for external folders"); //$NON-NLS-1$
return project;
} catch (IOException e) {
Util.log(e,
"Problem creating hidden project for external folders"); //$NON-NLS-1$
return project;
}
}
return project;
}
public synchronized IFolder getFolder(IPath externalFolderPath) {
return (IFolder) getFolders().get(externalFolderPath);
}
private HashMap getFolders() {
if (this.folders == null) {
this.folders = new HashMap();
IProject project = getExternalFoldersProject();
if (project.isAccessible()) {
try {
IResource[] members = project.members();
for (int i = 0, length = members.length; i < length; i++) {
IResource member = members[i];
if (member.getType() == IResource.FOLDER
&& member.isLinked() && member.getName()
.startsWith(LINKED_FOLDER_NAME)) {
IPath externalFolderPath = member.getLocation();
this.folders.put(externalFolderPath, member);
}
}
} catch (CoreException e) {
Util.log(e,
"Exception while initializing external folders"); //$NON-NLS-1$
}
}
}
return this.folders;
}
/*
* Refreshes the external folders referenced on the buildpath of the given
* source project
*/
public void refreshReferences(IProject source, IProgressMonitor monitor) {
IProject externalProject = getExternalFoldersProject();
if (source.equals(externalProject))
return;
if (!ScriptProject.hasScriptNature(source))
return;
try {
HashSet externalFolders = getExternalFolders(
((ScriptProject) DLTKCore.create(source))
.getResolvedBuildpath());
if (externalFolders == null)
return;
final Iterator iterator = externalFolders.iterator();
Job refreshJob = new Job(Messages.refreshing_external_folders) {
@Override
public boolean belongsTo(Object family) {
return family == ResourcesPlugin.FAMILY_MANUAL_REFRESH;
}
@Override
protected IStatus run(IProgressMonitor pm) {
try {
while (iterator.hasNext()) {
IPath externalPath = (IPath) iterator.next();
IFolder folder = getFolder(externalPath);
if (folder != null)
folder.refreshLocal(IResource.DEPTH_INFINITE,
pm);
}
} catch (CoreException e) {
return e.getStatus();
}
return Status.OK_STATUS;
}
};
refreshJob.schedule();
} catch (CoreException e) {
Util.log(e, "Exception while refreshing external project"); //$NON-NLS-1$
}
return;
}
public synchronized IFolder removeFolder(IPath externalFolderPath) {
return (IFolder) getFolders().remove(externalFolderPath);
}
}