/******************************************************************************* * Copyright (c) 2000, 2017 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 * * 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); } }