| /******************************************************************************* |
| * Copyright (c) 2005, 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.launching; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.transform.TransformerException; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.preferences.DefaultScope; |
| import org.eclipse.core.runtime.preferences.IEclipsePreferences; |
| import org.eclipse.core.runtime.preferences.InstanceScope; |
| import org.eclipse.core.variables.IStringVariableManager; |
| import org.eclipse.core.variables.VariablesPlugin; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.debug.core.sourcelookup.ISourceContainer; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.DLTKLanguageManager; |
| import org.eclipse.dltk.core.IBuildpathAttribute; |
| import org.eclipse.dltk.core.IBuildpathContainer; |
| import org.eclipse.dltk.core.IBuildpathEntry; |
| import org.eclipse.dltk.core.IDLTKLanguageToolkit; |
| import org.eclipse.dltk.core.IScriptModel; |
| import org.eclipse.dltk.core.IScriptProject; |
| import org.eclipse.dltk.core.environment.EnvironmentManager; |
| import org.eclipse.dltk.core.environment.EnvironmentPathUtils; |
| import org.eclipse.dltk.core.environment.IEnvironment; |
| import org.eclipse.dltk.core.environment.IFileHandle; |
| import org.eclipse.dltk.core.internal.environment.LocalEnvironment; |
| import org.eclipse.dltk.internal.launching.CompositeId; |
| import org.eclipse.dltk.internal.launching.DLTKLaunchingPlugin; |
| import org.eclipse.dltk.internal.launching.DefaultEntryResolver; |
| import org.eclipse.dltk.internal.launching.DefaultProjectBuildpathEntry; |
| import org.eclipse.dltk.internal.launching.InterpreterContainerInitializer; |
| import org.eclipse.dltk.internal.launching.InterpreterDefinitionsContainer; |
| import org.eclipse.dltk.internal.launching.InterpreterListener; |
| import org.eclipse.dltk.internal.launching.RuntimeBuildpathEntry; |
| import org.eclipse.dltk.internal.launching.RuntimeBuildpathEntryResolver; |
| import org.eclipse.dltk.internal.launching.RuntimeBuildpathProvider; |
| import org.eclipse.dltk.internal.launching.ScriptSourceLookupUtil; |
| import org.eclipse.osgi.util.NLS; |
| import org.osgi.framework.Bundle; |
| import org.osgi.service.prefs.BackingStoreException; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| |
| import com.ibm.icu.text.MessageFormat; |
| |
| /** |
| * The central access point for launching support. This class manages the |
| * registered interpreters types contributed through the |
| * <code>"org.eclipse.dltk.launching.interpreterType"</code> extension point. As |
| * well, this class provides interpreter install change notification, and |
| * computes buildpaths and source lookup paths for launch configurations. |
| * <p> |
| * This class provides static methods only; it is not intended to be |
| * instantiated or subclassed by clients. |
| * </p> |
| */ |
| public final class ScriptRuntime { |
| |
| /** |
| * Classpath container used for a project's InterpreterEnvironment (value |
| * <code>"org.eclipse.dltk.launching.INTERPRETER_CONTAINER"</code> ). A |
| * container is resolved in the context of a specific Script project, to one |
| * or more system libraries contained in a InterpreterEnvironment. The |
| * container can have zero or two path segments following the container |
| * name. When no segments follow the container name, the workspace default |
| * InterpreterEnvironment is used to build a project. Otherwise the segments |
| * identify a specific InterpreterEnvironment used to build a project: |
| * <ol> |
| * <li>Interpreter Install Type Identifier - identifies the type of |
| * InterpreterEnvironment used to build the project. For example, the |
| * standard Interpreter.</li> |
| * <li>Interpreter Install Name - a user defined name that identifies that a |
| * specific Interpreter of the above kind. For example, |
| * <code>IBM 1.3.1</code>. This information is shared in a projects |
| * buildpath file, so teams must agree on InterpreterEnvironment naming |
| * conventions.</li> |
| * </ol> |
| * <p> |
| * The path may also identify an execution environment as follows: |
| * <ol> |
| * <li>Execution environment extension point name (value |
| * <code>executionEnvironments</code>)</li> |
| * <li>Identifier of a contributed execution environment</li> |
| * </ol> |
| * </p> |
| * |
| */ |
| public static final String INTERPRETER_CONTAINER = DLTKLaunchingPlugin |
| .getUniqueIdentifier() + ".INTERPRETER_CONTAINER"; //$NON-NLS-1$ |
| |
| /** |
| * Simple identifier constant (value |
| * <code>"runtimeBuildpathEntryResolvers"</code>) for the runtime buildpath |
| * entry resolvers extension point. |
| */ |
| public static final String EXTENSION_POINT_RUNTIME_BUILDPATH_ENTRY_RESOLVERS = "runtimeBuildpathEntryResolvers"; //$NON-NLS-1$ |
| |
| /** |
| * Simple identifier constant (value <code>"buildpathProviders"</code>) for |
| * the runtime buildpath providers extension point. |
| */ |
| public static final String EXTENSION_POINT_RUNTIME_BUILDPATH_PROVIDERS = "buildpathProviders"; //$NON-NLS-1$ |
| |
| /** |
| * Simple identifier constant (value <code>"interpreterInstalls"</code>) for |
| * the interpreters installs extension point. |
| */ |
| public static final String EXTENSION_POINT_INTERPRETER_INSTALLS = "interpreterInstalls"; //$NON-NLS-1$ |
| |
| /** |
| * A status code indicating that a interpreter could not be resolved for a |
| * project. When a interpreter cannot be resolved for a project by this |
| * plug-in's container initializer, an exception is thrown with this status |
| * code. A status handler may be registered for this status code. The |
| * <code>source</code> object provided to the status handler is the script |
| * project for which the path could not be resolved. The status handler must |
| * return an <code>IInterpreterInstall</code> or <code>null</code>. The |
| * container resolver will re-set the project's buildpath if required. |
| */ |
| public static final int ERR_UNABLE_TO_RESOLVE_INTERPRETER = 160; |
| |
| /** |
| * Preference key for launch/connect timeout. Interpreter Runners should |
| * honor this timeout value when attempting to launch and connect to a |
| * debugger. The value is an int, indicating a number of milliseconds. |
| */ |
| public static final String PREF_CONNECT_TIMEOUT = DLTKLaunchingPlugin |
| .getUniqueIdentifier() + ".PREF_CONNECT_TIMEOUT"; //$NON-NLS-1$ |
| |
| /** |
| * Preference key for the String of XML that defines all installed |
| * Interpreters. |
| */ |
| public static final String PREF_INTERPRETER_XML = DLTKLaunchingPlugin |
| .getUniqueIdentifier() + ".PREF_INTERPRETER_XML"; //$NON-NLS-1$ |
| |
| /** |
| * Default launch/connect timeout (ms). |
| */ |
| public static final int DEF_CONNECT_TIMEOUT = 20000; |
| |
| /** |
| * Attribute key for a buildpath attribute referencing a list of shared |
| * libraries that should appear on the |
| * <code>-Dinterpreter.library.path</code> system property. |
| * <p> |
| * The factory methods <code>newLibraryPathsAttribute(String[])</code> and |
| * <code>getLibraryPaths(IBuildpathAttribute)</code> should be used to |
| * encode and decode the attribute value. |
| * </p> |
| * <p> |
| * Each string is used to create an <code>IPath</code> using the constructor |
| * <code>Path(String)</code>, and may contain <code>IStringVariable</code> |
| * 's. Variable substitution is performed on the string prior to |
| * constructing a path from the string. If the resulting <code>IPath</code> |
| * is a relative path, it is interpreted as relative to the workspace |
| * location. If the path is absolute, it is interpreted as an absolute path |
| * in the local file system. |
| * </p> |
| */ |
| public static final String BUILDPATH_ATTR_LIBRARY_PATH_ENTRY = DLTKLaunchingPlugin |
| .getUniqueIdentifier() + ".CLASSPATH_ATTR_LIBRARY_PATH_ENTRY"; //$NON-NLS-1$ |
| |
| // lock for interpreter initialization |
| private static Object fgInterpreterLock = new Object(); |
| private static boolean fgInitializingInterpreters = false; |
| |
| private static IInterpreterInstallType[] fgInterpreterTypes = null; |
| |
| /** |
| * This class is deprecated in 5.0 and should not be used outside of DLTK |
| * core plugins. The affected APIs will be updated, e.g. see |
| * {@link ScriptRuntime#getDefaultInterpreterInstall(String, IEnvironment)} |
| */ |
| @Deprecated |
| public static class DefaultInterpreterEntry { |
| private final String nature; |
| private final String environment; |
| |
| public DefaultInterpreterEntry(String nature, String environment) { |
| this.nature = nature; |
| this.environment = environment; |
| } |
| |
| public String getNature() { |
| return nature; |
| } |
| |
| public String getEnvironment() { |
| return environment; |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result |
| + ((environment == null) ? 0 : environment.hashCode()); |
| result = prime * result |
| + ((nature == null) ? 0 : nature.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| DefaultInterpreterEntry other = (DefaultInterpreterEntry) obj; |
| if (environment == null) { |
| if (other.environment != null) |
| return false; |
| } else if (!environment.equals(other.environment)) |
| return false; |
| if (nature == null) { |
| if (other.nature != null) |
| return false; |
| } else if (!nature.equals(other.nature)) |
| return false; |
| return true; |
| } |
| |
| @Override |
| public String toString() { |
| return nature + "/" + environment; //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Contain association of default interpreter entries to interprter |
| * identifiers. |
| */ |
| private static Map<DefaultInterpreterEntry, String> fgDefaultInterpreterId = new HashMap<>(); |
| |
| /** |
| * Contain DefaultInterpreterEntry entry assocications |
| */ |
| private static Map<DefaultInterpreterEntry, String> fgDefaultInterpreterConnectorId = new HashMap<>(); |
| |
| /** |
| * Resolvers keyed by variable name, container id, and runtime buildpath |
| * entry id. |
| */ |
| private static Map<String, IRuntimeBuildpathEntryResolver> fgContainerResolvers = null; |
| private static Map<String, IRuntimeBuildpathEntryResolver> fgRuntimeBuildpathEntryResolvers = null; |
| |
| /** |
| * Path providers keyed by id |
| */ |
| private static Map<String, IRuntimeBuildpathProvider> fgPathProviders = null; |
| |
| /** |
| * Default buildpath and source path providers. |
| */ |
| private static IRuntimeBuildpathProvider fgDefaultBuildpathProvider = new StandardBuildpathProvider(); |
| private static IRuntimeBuildpathProvider fgDefaultSourcepathProvider = new StandardSourcepathProvider(); |
| |
| /** |
| * Interpreter change listeners |
| */ |
| private static ListenerList fgInterpreterListeners = new ListenerList( |
| ListenerList.IDENTITY); |
| |
| /** |
| * Cache of already resolved projects in container entries. Used to avoid |
| * cycles in project dependencies when resolving buildpath container |
| * entries. Counters used to know when entering/exiting to clear cache |
| */ |
| private static ThreadLocal<List<IScriptProject>> fgProjects = new ThreadLocal<>(); |
| private static ThreadLocal<Integer> fgEntryCount = new ThreadLocal<>(); |
| |
| /** |
| * Set of IDs of Interpreters contributed via InterpreterInstalls extension |
| * point. |
| */ |
| private static Set<String> fgContributedInterpreters = new HashSet<>(); |
| |
| /** |
| * This class contains only static methods, and is not intended to be |
| * instantiated. |
| */ |
| private ScriptRuntime() { |
| } |
| |
| /** |
| * Initializes interpreter type extensions. |
| */ |
| private static void initializeInterpreterTypeExtensions() { |
| IExtensionPoint extensionPoint = Platform.getExtensionRegistry() |
| .getExtensionPoint(DLTKLaunchingPlugin.PLUGIN_ID, |
| "interpreterInstallTypes"); //$NON-NLS-1$ |
| IConfigurationElement[] configs = extensionPoint |
| .getConfigurationElements(); |
| |
| MultiStatus status = new MultiStatus( |
| DLTKLaunchingPlugin.getUniqueIdentifier(), IStatus.OK, |
| LaunchingMessages.ScriptRuntime_exceptionsOccurred, null); |
| fgInterpreterTypes = new IInterpreterInstallType[configs.length]; |
| |
| for (int i = 0; i < configs.length; i++) { |
| try { |
| IInterpreterInstallType installType = (IInterpreterInstallType) configs[i] |
| .createExecutableExtension("class"); //$NON-NLS-1$ |
| fgInterpreterTypes[i] = installType; |
| } catch (CoreException e) { |
| status.add(e.getStatus()); |
| } |
| } |
| if (!status.isOK()) { |
| // only happens on a CoreException |
| DLTKLaunchingPlugin.log(status); |
| // cleanup null entries in fgInterpreterTypes |
| List<IInterpreterInstallType> temp = new ArrayList<>( |
| fgInterpreterTypes.length); |
| for (int i = 0; i < fgInterpreterTypes.length; i++) { |
| if (fgInterpreterTypes[i] != null) { |
| temp.add(fgInterpreterTypes[i]); |
| } |
| fgInterpreterTypes = temp |
| .toArray(new IInterpreterInstallType[temp.size()]); |
| } |
| } |
| } |
| |
| private static String getNatureFromProject(IScriptProject project) { |
| try { |
| IDLTKLanguageToolkit toolkit = DLTKLanguageManager |
| .getLanguageToolkit(project); |
| if (toolkit != null) |
| return toolkit.getNatureId(); |
| } catch (Exception e) { |
| DLTKLaunchingPlugin.log(e); |
| } |
| return null; |
| } |
| |
| private static String getEnvironmentFromProject(IScriptProject project) { |
| return EnvironmentManager.getEnvironmentId(project.getProject()); |
| } |
| |
| /** |
| * Returns the interpreter assigned to build the given script project. The |
| * project must exist. The interpreter assigned to a project is determined |
| * from its build path. |
| * |
| * @param project |
| * the project to retrieve the interpreter from |
| * @return the interpreter instance that is assigned to build the given |
| * script project Returns <code>null</code> if no interp. is |
| * referenced on the project's build path. |
| * @throws CoreException |
| * if unable to determine the project's interpreter install |
| */ |
| public static IInterpreterInstall getInterpreterInstall( |
| IScriptProject project) throws CoreException { |
| // check the buildpath |
| IInterpreterInstall interpreter = null; |
| |
| IBuildpathEntry[] buildpath = project.getRawBuildpath(); |
| |
| for (int i = 0; i < buildpath.length; i++) { |
| IBuildpathEntry entry = buildpath[i]; |
| switch (entry.getEntryKind()) { |
| case IBuildpathEntry.BPE_CONTAINER: |
| IRuntimeBuildpathEntryResolver resolver = getContainerResolver( |
| entry.getPath().segment(0)); |
| if (resolver != null) { |
| interpreter = resolver.resolveInterpreterInstall( |
| getNatureFromProject(project), |
| getEnvironmentFromProject(project), entry); |
| } |
| break; |
| } |
| |
| if (interpreter != null) { |
| return interpreter; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the interpreter install type with the given unique id. |
| * |
| * @param id |
| * the interpreter install type unique id |
| * @return The interpreter install type for the given id, or |
| * <code>null</code> if no interpreter install type with the given |
| * id is registered. |
| */ |
| public static IInterpreterInstallType getInterpreterInstallType(String id) { |
| IInterpreterInstallType[] installTypes = getInterpreterInstallTypes(); |
| if (installTypes == null) { |
| return null; |
| } |
| |
| for (int i = 0; i < installTypes.length; i++) { |
| IInterpreterInstallType type = installTypes[i]; |
| if (type != null && type.getId().equals(id)) { |
| return type; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Sets a Interpreter as the system-wide default Interpreter, and notifies |
| * registered Interpreter install change listeners of the change. |
| * |
| * @param interpreter |
| * The Interpreter to make the default. May be <code>null</code> |
| * to clear the default. |
| * @param monitor |
| * progress monitor or <code>null</code> |
| */ |
| public static void setDefaultInterpreterInstall( |
| IInterpreterInstall interpreter, IProgressMonitor monitor) |
| throws CoreException { |
| setDefaultInterpreterInstall(interpreter, monitor, true); |
| } |
| |
| /** |
| * Sets a Interpreter as the nature default Interpreter, and notifies |
| * registered Interpreter install change listeners of the change. |
| * |
| * @param interpreter |
| * The Interpreter to make the default. May be <code>null</code> |
| * to clear the default. |
| * @param monitor |
| * progress monitor or <code>null</code> |
| * @param savePreference |
| * If <code>true</code>, update workbench preferences to reflect |
| * the new default Interpreter. |
| * |
| */ |
| public static void setDefaultInterpreterInstall( |
| IInterpreterInstall interpreter, IProgressMonitor monitor, |
| boolean savePreference) throws CoreException { |
| final IEnvironment env = interpreter.getEnvironment(); |
| if (env == null) { |
| return; |
| } |
| final String environmentId = env.getId(); |
| IInterpreterInstall previous = null; |
| String nature = interpreter.getInterpreterInstallType().getNatureId(); |
| |
| DefaultInterpreterEntry defaultInterpreterID = new DefaultInterpreterEntry( |
| nature, environmentId); |
| if (fgDefaultInterpreterId.get(defaultInterpreterID) != null) { |
| previous = getInterpreterFromCompositeId( |
| fgDefaultInterpreterId.get(defaultInterpreterID)); |
| } |
| fgDefaultInterpreterId.put(defaultInterpreterID, |
| getCompositeIdFromInterpreter(interpreter)); |
| if (savePreference) { |
| saveInterpreterConfiguration(); |
| } |
| IInterpreterInstall current = null; |
| if (fgDefaultInterpreterId.get(defaultInterpreterID) != null) { |
| current = getInterpreterFromCompositeId( |
| fgDefaultInterpreterId.get(defaultInterpreterID)); |
| } |
| if (previous != current) { |
| notifyDefaultInterpreterChanged(previous, current); |
| } |
| } |
| |
| /** |
| * Return the default interpreter set with |
| * <code>setDefaultInterpreter()</code> for the specified |
| * <code>natureId</code> and <code>environment</code> or <code>null</code>. |
| */ |
| public static IInterpreterInstall getDefaultInterpreterInstall( |
| String natureId, IEnvironment environment) { |
| return getDefaultInterpreterInstall(new DefaultInterpreterEntry( |
| natureId, environment != null ? environment.getId() |
| : LocalEnvironment.ENVIRONMENT_ID)); |
| } |
| |
| /** |
| * Return the default Interpreter set with |
| * <code>setDefaultInterpreter()</code>. |
| * |
| * @return Returns the default Interpreter. |
| */ |
| @Deprecated |
| public static IInterpreterInstall getDefaultInterpreterInstall( |
| DefaultInterpreterEntry entry) { |
| IInterpreterInstall install = getInterpreterFromCompositeId( |
| getDefaultInterpreterId(entry)); |
| if (install != null && install.getInstallLocation().exists()) { |
| return install; |
| } |
| // if the default interp. goes missing, re-detect |
| if (install != null) { |
| // install.getInterpreterInstallType().disposeInterpreterInstall( |
| // install.getId()); |
| } |
| if (!hasInterpreterInstalls(entry.getNature(), |
| entry.getEnvironment())) { |
| /* |
| * If there are no any interpreters for the specified nature and |
| * environment - just return null and avoid re-initialization. |
| * Generally speaking user should not be forced to configure every |
| * interpreter for every host. |
| */ |
| return null; |
| } |
| synchronized (fgInterpreterLock) { |
| // fgDefaultInterpreterId = null; |
| fgDefaultInterpreterId.clear(); |
| fgInterpreterTypes = null; |
| initializeInterpreters(); |
| } |
| |
| return getInterpreterFromCompositeId(getDefaultInterpreterId(entry)); |
| } |
| |
| /** |
| * Tests if there are any interpreters for the specified nature and host. |
| * |
| * @param natureId |
| * @param environmentId |
| * @return |
| */ |
| private static boolean hasInterpreterInstalls(String natureId, |
| String environmentId) { |
| if (environmentId == null) { |
| return false; |
| } |
| for (IInterpreterInstallType type : getInterpreterInstallTypes( |
| natureId)) { |
| for (IInterpreterInstall install : type.getInterpreterInstalls()) { |
| if (environmentId.equals(install.getEnvironmentId())) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the list of registered interpreter types. Interpreter types are |
| * registered via <code>"org.eclipse.dltk.launching.interpreterTypes"</code> |
| * extension point. Returns an empty list if there are no registered |
| * interpreter types. |
| * |
| * @return the list of registered Interpreter types |
| */ |
| public static IInterpreterInstallType[] getInterpreterInstallTypes() { |
| initializeInterpreters(); |
| return fgInterpreterTypes; |
| } |
| |
| /** |
| * Returns FILTERED list of registered interpreter types. Interpreter types |
| * are registered via |
| * <code>"org.eclipse.dltk.launching.interpreterTypes"</code> extension |
| * point. Returns an empty list if there are no registered interpreter |
| * types. |
| * |
| * @return the list of registered Interpreter types |
| */ |
| public static IInterpreterInstallType[] getInterpreterInstallTypes( |
| String nature) { |
| List<IInterpreterInstallType> res = new ArrayList<>(); |
| synchronized (fgInterpreterLock) { |
| initializeInterpreters(); |
| for (int i = 0; i < fgInterpreterTypes.length; i++) { |
| IInterpreterInstallType t = fgInterpreterTypes[i]; |
| if (t.getNatureId().equals(nature)) |
| res.add(t); |
| } |
| } |
| return res.toArray(new IInterpreterInstallType[res.size()]); |
| } |
| |
| public static DefaultInterpreterEntry[] getDefaultInterpreterIDs() { |
| Set<DefaultInterpreterEntry> set = fgDefaultInterpreterId.keySet(); |
| return set.toArray(new DefaultInterpreterEntry[set.size()]); |
| } |
| |
| private static String getDefaultInterpreterId( |
| DefaultInterpreterEntry entry) { |
| initializeInterpreters(); |
| return fgDefaultInterpreterId.get(entry); |
| } |
| |
| private static String getDefaultInterpreterConnectorId( |
| DefaultInterpreterEntry entry) { |
| initializeInterpreters(); |
| return fgDefaultInterpreterConnectorId.get(entry); |
| } |
| |
| /** |
| * Returns a String that uniquely identifies the specified Interpreter |
| * across all Interpreter types. |
| * |
| * @param interpreter |
| * the instance of IInterpreterInstallType to be identified |
| * |
| * |
| */ |
| public static String getCompositeIdFromInterpreter( |
| IInterpreterInstall interpreter) { |
| if (interpreter == null) { |
| return null; |
| } |
| IInterpreterInstallType interpreterType = interpreter |
| .getInterpreterInstallType(); |
| String typeID = interpreterType.getId(); |
| CompositeId id = new CompositeId( |
| new String[] { typeID, interpreter.getId() }); |
| return id.toString(); |
| } |
| |
| /** |
| * Return the Interpreter corresponding to the specified composite Id. The |
| * id uniquely identifies a Interpreter across all Interpreter types. |
| * |
| * @param idString |
| * the composite id that specifies an instance of |
| * IInterpreterInstall |
| * |
| * |
| */ |
| public static IInterpreterInstall getInterpreterFromCompositeId( |
| String idString) { |
| if (idString == null || idString.length() == 0) { |
| return null; |
| } |
| CompositeId id = CompositeId.fromString(idString); |
| if (id.getPartCount() == 2) { |
| IInterpreterInstallType InterpreterType = getInterpreterInstallType( |
| id.get(0)); |
| if (InterpreterType != null) { |
| return InterpreterType.findInterpreterInstall(id.get(1)); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Return the <code>IScriptProject</code> referenced in the specified |
| * configuration or <code>null</code> if none. |
| * |
| * @exception CoreException |
| * if the referenced Script project does not exist |
| * |
| */ |
| public static IScriptProject getScriptProject( |
| ILaunchConfiguration configuration) throws CoreException { |
| String projectName = configuration.getAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_PROJECT_NAME, |
| (String) null); |
| if ((projectName == null) || (projectName.trim().length() < 1)) { |
| return null; |
| } |
| IScriptProject scriptProject = getScriptModel() |
| .getScriptProject(projectName); |
| if (scriptProject != null && scriptProject.getProject().exists() |
| && !scriptProject.getProject().isOpen()) { |
| abort(MessageFormat.format(LaunchingMessages.ScriptRuntime_28, |
| configuration.getName(), projectName), |
| ScriptLaunchConfigurationConstants.ERR_PROJECT_CLOSED, |
| null); |
| } |
| if ((scriptProject == null) || !scriptProject.exists()) { |
| abort(MessageFormat.format( |
| LaunchingMessages.ScriptRuntime_Launch_configuration__0__references_non_existing_project__1___1, |
| configuration.getName(), projectName), |
| ScriptLaunchConfigurationConstants.ERR_NOT_A_SCRIPT_PROJECT, |
| null); |
| } |
| return scriptProject; |
| } |
| |
| /** |
| * Convenience method to get the script model. |
| */ |
| private static IScriptModel getScriptModel() { |
| return DLTKCore.create(ResourcesPlugin.getWorkspace().getRoot()); |
| } |
| |
| /** |
| * Returns the Interpreter install for the given launch configuration. The |
| * Interpreter install is determined in the following prioritized way: |
| * <ol> |
| * <li>The Interpreter install is explicitly specified on the launch |
| * configuration via the <code>ATTR_CONTAINER_PATH</code> attribute.</li> |
| * <li>If no explicit Interpreter install is specified, the Interpreter |
| * install associated with the launch configuration's project is |
| * returned.</li> |
| * <li>If no project is specified, or the project does not specify a custom |
| * Interpreter install, the workspace default Interpreter install is |
| * returned.</li> |
| * </ol> |
| * |
| * @param configuration |
| * launch configuration |
| * @return interpreter install |
| * @exception CoreException |
| * if unable to compute a Interpreter install |
| * |
| */ |
| public static IInterpreterInstall computeInterpreterInstall( |
| ILaunchConfiguration configuration) throws CoreException { |
| // get field ATTR_NATURE from launch configuration |
| String nature = configuration.getAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_SCRIPT_NATURE, |
| (String) null); |
| String containerPath = configuration.getAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_CONTAINER_PATH, |
| (String) null); |
| IScriptProject proj = getScriptProject(configuration); |
| String environment = getEnvironmentFromProject(proj); |
| if (containerPath == null) { |
| if (proj != null) { |
| IInterpreterInstall install = getInterpreterInstall(proj); |
| if (install != null) { |
| return install; |
| } |
| if (nature == null) { |
| IDLTKLanguageToolkit tk = DLTKLanguageManager |
| .getLanguageToolkit(proj); |
| nature = tk.getNatureId(); |
| } |
| } |
| } else { |
| IPath interpreterPath = Path.fromPortableString(containerPath); |
| IBuildpathEntry entry = DLTKCore.newContainerEntry(interpreterPath); |
| IRuntimeBuildpathEntryResolver2 resolver = getContainerResolver( |
| interpreterPath.segment(0)); |
| if (resolver != null) { |
| return resolver.resolveInterpreterInstall(nature, environment, |
| entry); |
| } else { |
| resolver = getContainerResolver(interpreterPath.segment(0)); |
| if (resolver != null) { |
| return resolver.resolveInterpreterInstall(nature, |
| environment, entry); |
| } |
| } |
| } |
| |
| if (nature == null) { |
| abort(LaunchingMessages.ScriptRuntime_notDefaultInterpreter, |
| ScriptLaunchConfigurationConstants.ERR_NO_DEFAULT_INTERPRETER_INSTALL, |
| null); |
| } |
| // OR extract project nature from it's name (what about several |
| // natures?) |
| DefaultInterpreterEntry entry = new DefaultInterpreterEntry(nature, |
| environment); |
| IInterpreterInstall res = getDefaultInterpreterInstall(entry); |
| if (res == null) { |
| abort(LaunchingMessages.ScriptRuntime_notDefaultInterpreter, |
| ScriptLaunchConfigurationConstants.ERR_NO_DEFAULT_INTERPRETER_INSTALL, |
| null); |
| } |
| return res; |
| } |
| |
| /** |
| * Throws a core exception with an internal error status. |
| * |
| * @param message |
| * the status message |
| * @param exception |
| * lower level exception associated with the error, or |
| * <code>null</code> if none |
| */ |
| private static CoreException abort(String message, Throwable exception) |
| throws CoreException { |
| throw abort(message, |
| ScriptLaunchConfigurationConstants.ERR_INTERNAL_ERROR, |
| exception); |
| } |
| |
| /** |
| * Throws a core exception with an internal error status. |
| * |
| * @param message |
| * the status message |
| * @param code |
| * status code |
| * @param exception |
| * lower level exception associated with the |
| * |
| * error, or <code>null</code> if none |
| */ |
| private static CoreException abort(String message, int code, |
| Throwable exception) throws CoreException { |
| throw new CoreException(new Status(IStatus.ERROR, |
| DLTKLaunchingPlugin.PLUGIN_ID, code, message, exception)); |
| } |
| |
| /** |
| * Saves the Interpreter configuration information to the preferences. This |
| * includes the following information: |
| * <ul> |
| * <li>The list of all defined IInterpreterInstall instances.</li> |
| * <li>The default Interpreter</li> |
| * <ul> |
| * This state will be read again upon first access to Interpreter |
| * configuration information. |
| */ |
| public static void saveInterpreterConfiguration() throws CoreException { |
| if (fgInterpreterTypes == null) { |
| // if the Interpreter types have not been instantiated, there can be |
| // no changes. |
| return; |
| } |
| try { |
| String xml = getInterpretersAsXML(); |
| getPreferences().put(PREF_INTERPRETER_XML, xml); |
| savePreferences(); |
| } catch (IOException e) { |
| throw new CoreException(new Status(IStatus.ERROR, |
| DLTKLaunchingPlugin.getUniqueIdentifier(), IStatus.ERROR, |
| LaunchingMessages.ScriptRuntime_exceptionsOccurred, e)); |
| } catch (ParserConfigurationException e) { |
| throw new CoreException(new Status(IStatus.ERROR, |
| DLTKLaunchingPlugin.getUniqueIdentifier(), IStatus.ERROR, |
| LaunchingMessages.ScriptRuntime_exceptionsOccurred, e)); |
| } catch (TransformerException e) { |
| throw new CoreException(new Status(IStatus.ERROR, |
| DLTKLaunchingPlugin.getUniqueIdentifier(), IStatus.ERROR, |
| LaunchingMessages.ScriptRuntime_exceptionsOccurred, e)); |
| } |
| } |
| |
| private static String getInterpretersAsXML() throws IOException, |
| ParserConfigurationException, TransformerException { |
| InterpreterDefinitionsContainer container = new InterpreterDefinitionsContainer(); |
| |
| DefaultInterpreterEntry[] entries = getDefaultInterpreterIDs(); |
| for (int i = 0; i < entries.length; i++) { |
| String id = getDefaultInterpreterId(entries[i]); |
| if (id != null) |
| container.setDefaultInterpreterInstallCompositeID(entries[i], |
| id); |
| id = getDefaultInterpreterConnectorId(entries[i]); |
| if (id != null) |
| container.setDefaultInterpreterInstallConnectorTypeID( |
| entries[i], id); |
| } |
| |
| IInterpreterInstallType[] InterpreterTypes = getInterpreterInstallTypes(); |
| for (int i = 0; i < InterpreterTypes.length; ++i) { |
| IInterpreterInstall[] Interpreters = InterpreterTypes[i] |
| .getInterpreterInstalls(); |
| for (int j = 0; j < Interpreters.length; j++) { |
| IInterpreterInstall install = Interpreters[j]; |
| container.addInterpreter(install); |
| } |
| } |
| return container.getAsXML(); |
| } |
| |
| /** |
| * This method loads installed interpreters based an existing user |
| * preference or old Interpreter configurations file. The interpreters found |
| * in the preference or interpreter configurations file are added to the |
| * given Interpreter definitions container. |
| * |
| * Returns whether the user preferences should be set - i.e. if it was not |
| * already set when initialized. |
| */ |
| private static boolean addPersistedInterpreters( |
| InterpreterDefinitionsContainer interpreterDefs) { |
| // Try retrieving the interpreter preferences from the preference store |
| String interpreterXMLString = getPreferences().get(PREF_INTERPRETER_XML, |
| ""); |
| |
| if (interpreterXMLString.length() == 0) { |
| // default scope value could be specified in the |
| // plugin_customization.ini file |
| interpreterXMLString = DefaultScope.INSTANCE |
| .getNode(DLTKLaunchingPlugin.PLUGIN_ID) |
| .get(PREF_INTERPRETER_XML, ""); |
| } |
| |
| // If the preference was found, load interpreters from it into memory |
| if (interpreterXMLString.length() > 0) { |
| try { |
| Reader inputStream = new StringReader(interpreterXMLString); |
| InterpreterDefinitionsContainer |
| .parseXMLIntoContainer(inputStream, interpreterDefs); |
| return false; |
| } catch (IOException ioe) { |
| DLTKLaunchingPlugin.log(ioe); |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Performs string substitution on the given expression. |
| * |
| * @param expression |
| * @return expression after string substitution |
| * @throws CoreException |
| * |
| */ |
| private static String substitute(String expression) throws CoreException { |
| return VariablesPlugin.getDefault().getStringVariableManager() |
| .performStringSubstitution(expression); |
| } |
| |
| /** |
| * Returns whether the Interpreter install with the specified id was |
| * contributed via the InterpreterInstalls extension point. |
| * |
| * @param id |
| * Interpreter id |
| * @return whether the Interpreter install was contributed via extension |
| * point |
| * |
| */ |
| public static boolean isContributedInterpreterInstall(String id) { |
| getInterpreterInstallTypes(); // ensure Interpreters are initialized |
| return fgContributedInterpreters.contains(id); |
| } |
| |
| /** |
| * Evaluates library locations for a IInterpreterInstall. If no library |
| * locations are set on the install, a default location is evaluated and |
| * checked if it exists. |
| * |
| * @return library locations with paths that exist or are empty |
| * |
| */ |
| public static LibraryLocation[] getLibraryLocations( |
| IInterpreterInstall interperterInstall) { |
| return getLibraryLocations(interperterInstall, null); |
| } |
| |
| public static LibraryLocation[] getLibraryLocations( |
| IInterpreterInstall interperterInstall, IProgressMonitor monitor) { |
| |
| LibraryLocation[] locations = interperterInstall.getLibraryLocations(); |
| if (locations != null) { |
| return locations; |
| } |
| |
| LibraryLocation[] defaultLocations = interperterInstall |
| .getInterpreterInstallType().getDefaultLibraryLocations( |
| interperterInstall.getInstallLocation(), |
| interperterInstall.getEnvironmentVariables(), monitor); |
| |
| List<LibraryLocation> existingDefaultLocations = new ArrayList<>(); |
| for (int i = 0; i < defaultLocations.length; ++i) { |
| LibraryLocation location = defaultLocations[i]; |
| |
| IFileHandle file = EnvironmentPathUtils |
| .getFile(location.getLibraryPath()); |
| if (file.exists()) { |
| existingDefaultLocations.add(location); |
| } |
| } |
| |
| return existingDefaultLocations |
| .toArray(new LibraryLocation[existingDefaultLocations.size()]); |
| } |
| |
| /** |
| * Creates and returns a buildpath entry describing the default interpreter |
| * container entry. |
| * |
| * @return a new IBuildpathEntry that describes the default interpreter |
| * container entry |
| * |
| */ |
| public static IBuildpathEntry getDefaultInterpreterContainerEntry() { |
| return DLTKCore.newContainerEntry(newDefaultInterpreterContainerPath()); |
| } |
| |
| /** |
| * Returns a path for the interpreter buildpath container identifying the |
| * default interpreter install. |
| * |
| * @return buildpath container path |
| * |
| */ |
| public static IPath newDefaultInterpreterContainerPath() { |
| return new Path(INTERPRETER_CONTAINER); |
| } |
| |
| /** |
| * Returns a path for the interpreter buildpath container identifying the |
| * specified Interpreter install by type and name. |
| * |
| * @param Interpreter |
| * Interpreter install |
| * @return buildpath container path |
| * |
| */ |
| public static IPath newInterpreterContainerPath( |
| IInterpreterInstall interpreter) { |
| if (interpreter != null) { |
| String name = interpreter.getName(); |
| String typeId = interpreter.getInterpreterInstallType().getId(); |
| return newInterpreterContainerPath(typeId, name); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a path for the InterpreterEnvironment buildpath container |
| * identifying the specified Interpreter install by type and name. |
| * |
| * @param typeId |
| * Interpreter install type identifier |
| * @param name |
| * Interpreter install name |
| * @return buildpath container path |
| * |
| */ |
| public static IPath newInterpreterContainerPath(String typeId, |
| String name) { |
| if (typeId == null || name == null) { |
| return null; |
| } |
| |
| IPath path = newDefaultInterpreterContainerPath(); |
| path = path.append(typeId); |
| path = path.append(name.replaceAll("/", "%2F")); //$NON-NLS-1$ //$NON-NLS-2$ |
| return path; |
| } |
| |
| /** |
| * Returns the InterpreterEnvironment referenced by the specified |
| * InterpreterEnvironment buildpath container path or <code>null</code> if |
| * none. |
| * |
| * @param InterpreterEnvironmentContainerPath |
| * @return InterpreterEnvironment referenced by the specified |
| * InterpreterEnvironment buildpath container path or |
| * <code>null</code> |
| * |
| */ |
| public static IInterpreterInstall getInterpreterInstall(String nature, |
| String environment, IPath InterpreterEnvironmentContainerPath) { |
| try { |
| return InterpreterContainerInitializer.resolveInterpreter(nature, |
| environment, InterpreterEnvironmentContainerPath); |
| } catch (CoreException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the <code>IInterpreterInstall</code> represented by the specified |
| * <code>compositeId</code>. |
| * |
| * <p> |
| * If an interpreter can not be found for the given <code>compositeId</code> |
| * , the default interpreter for the specified <code>natureId</code> will be |
| * returned. |
| * |
| * If no default interpreter has been configured, <code>null</code> will be |
| * returned. |
| * </p> |
| * |
| * @param compositeId |
| * the composite id that specifies an instance of |
| * IInterpreterInstall |
| * @param natureId |
| * nature id |
| * |
| * @return IInterpreterInstall instance or <code>null</code> if one can not |
| * be found. |
| */ |
| public static IInterpreterInstall getInterpreterInstall(String compositeId, |
| String natureId) { |
| IInterpreterInstall install = getInterpreterFromCompositeId( |
| compositeId); |
| if (install == null) { |
| DefaultInterpreterEntry entry = new DefaultInterpreterEntry( |
| natureId, LocalEnvironment.ENVIRONMENT_ID); |
| install = ScriptRuntime.getDefaultInterpreterInstall(entry); |
| } |
| |
| return install; |
| } |
| |
| /** |
| * Returns the identifier of the Interpreter install type referenced by the |
| * given InterpreterEnvironment buildpath container path, or |
| * <code>null</code> if none. |
| * |
| * @param InterpreterEnvironmentContainerPath |
| * @return Interpreter install type identifier or <code>null</code> |
| * |
| */ |
| public static String getInterpreterInstallTypeId( |
| IPath InterpreterEnvironmentContainerPath) { |
| return InterpreterContainerInitializer |
| .getInterpreterTypeId(InterpreterEnvironmentContainerPath); |
| } |
| |
| /** |
| * Returns the name of the Interpreter install referenced by the given |
| * InterpreterEnvironment buildpath container path, or <code>null</code> if |
| * none. |
| * |
| * @param InterpreterEnvironmentContainerPath |
| * @return Interpreter name or <code>null</code> |
| * |
| */ |
| public static String getInterpreterInstallName( |
| IPath InterpreterEnvironmentContainerPath) { |
| return InterpreterContainerInitializer |
| .getInterpreterName(InterpreterEnvironmentContainerPath); |
| } |
| |
| /** |
| * Returns a runtime buildpath entry identifying the InterpreterEnvironment |
| * to use when launching the specified configuration or <code>null</code> if |
| * none is specified. The entry returned represents a either abuildpath |
| * container that resolves to a interpreter. |
| * <p> |
| * The entry is resolved as follows: |
| * <ol> |
| * <li>If the <code>ATTR_CONTAINER_PATH</code> is present, it is used to |
| * create a buildpath container referring to a interpreter.</li> |
| * <li>When such attribute are not specified, a default entry is created |
| * which refers to the interpreter referenced by the build path of the |
| * configuration's associated script project. This could be a buildpath |
| * variable or buildpath container.</li> |
| * <li>When there is no script project associated with a configuration, the |
| * workspace default interpreter is used to create a container path.</li> |
| * </ol> |
| * </p> |
| * |
| * @param configuration |
| * @return buildpath container path identifying a interpreter or |
| * <code>null</code> |
| * @exception org.eclipse.core.runtime.CoreException |
| * if an exception occurs retrieving attributes from the |
| * specified launch configuration |
| */ |
| public static IRuntimeBuildpathEntry computeInterpreterEntry( |
| ILaunchConfiguration configuration) throws CoreException { |
| String containerAttr = configuration.getAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_CONTAINER_PATH, |
| (String) null); |
| IPath containerPath = null; |
| if (containerAttr == null) { |
| // default interpreter for the launch configuration |
| IScriptProject proj = getScriptProject(configuration); |
| if (proj == null) { |
| containerPath = newDefaultInterpreterContainerPath(); |
| } else { |
| return computeInterpreterEntry(proj); |
| } |
| } else { |
| containerPath = Path.fromPortableString(containerAttr); |
| } |
| if (containerPath != null) { |
| return newRuntimeContainerBuildpathEntry(containerPath, |
| IRuntimeBuildpathEntry.STANDARD_ENTRY); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a runtime buildpath entry identifying the InterpreterEnvironment |
| * referenced by the specified project, or <code>null</code> if none. The |
| * entry returned represents a either a buildpath variable or buildpath |
| * container that resolves to a InterpreterEnvironment. |
| * |
| * @param project |
| * Script project |
| * @return InterpreterEnvironment runtime buildpath entry or |
| * <code>null</code> |
| * @exception org.eclipse.core.runtime.CoreException |
| * if an exception occurs accessing the project's buildpath |
| * |
| */ |
| public static IRuntimeBuildpathEntry computeInterpreterEntry( |
| IScriptProject project) throws CoreException { |
| IBuildpathEntry[] rawBuildpath = project.getRawBuildpath(); |
| IRuntimeBuildpathEntryResolver2 resolver = null; |
| for (int i = 0; i < rawBuildpath.length; i++) { |
| IBuildpathEntry entry = rawBuildpath[i]; |
| switch (entry.getEntryKind()) { |
| case IBuildpathEntry.BPE_CONTAINER: |
| resolver = getContainerResolver(entry.getPath().segment(0)); |
| if (resolver != null) { |
| if (resolver.isInterpreterInstallReference( |
| getNatureFromProject(project), |
| getEnvironmentFromProject(project), entry)) { |
| IBuildpathContainer container = DLTKCore |
| .getBuildpathContainer(entry.getPath(), |
| project); |
| if (container != null) { |
| switch (container.getKind()) { |
| case IBuildpathContainer.K_APPLICATION: |
| break; |
| case IBuildpathContainer.K_DEFAULT_SYSTEM: |
| return newRuntimeContainerBuildpathEntry( |
| entry.getPath(), |
| IRuntimeBuildpathEntry.STANDARD_ENTRY); |
| case IBuildpathContainer.K_SYSTEM: |
| return newRuntimeContainerBuildpathEntry( |
| entry.getPath(), |
| IRuntimeBuildpathEntry.BOOTSTRAP_ENTRY); |
| } |
| } |
| } |
| } |
| break; |
| } |
| |
| } |
| return null; |
| } |
| |
| /** |
| * Returns whether the given runtime buildpath entry refers to a Interpreter |
| * install. |
| * |
| * @param entry |
| * @return whether the given runtime buildpath entry refers to a Interpreter |
| * install |
| * |
| */ |
| public static boolean isInterpreterInstallReference(String lang, |
| String environment, IRuntimeBuildpathEntry entry) { |
| IBuildpathEntry buildpathEntry = entry.getBuildpathEntry(); |
| if (buildpathEntry != null) { |
| switch (buildpathEntry.getEntryKind()) { |
| case IBuildpathEntry.BPE_CONTAINER: |
| IRuntimeBuildpathEntryResolver2 resolver = getContainerResolver( |
| buildpathEntry.getPath().segment(0)); |
| if (resolver != null) { |
| return resolver.isInterpreterInstallReference(lang, |
| environment, buildpathEntry); |
| } |
| break; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Adds the given listener to the list of registered Interpreter install |
| * changed listeners. Has no effect if an identical listener is already |
| * registered. |
| * |
| * @param listener |
| * the listener to add |
| * |
| */ |
| public static void addInterpreterInstallChangedListener( |
| IInterpreterInstallChangedListener listener) { |
| fgInterpreterListeners.add(listener); |
| } |
| |
| /** |
| * Removes the given listener from the list of registered Interpreter |
| * install changed listeners. Has no effect if an identical listener is not |
| * already registered. |
| * |
| * @param listener |
| * the listener to remove |
| * |
| */ |
| public static void removeInterpreterInstallChangedListener( |
| IInterpreterInstallChangedListener listener) { |
| fgInterpreterListeners.remove(listener); |
| } |
| |
| private static void notifyDefaultInterpreterChanged( |
| IInterpreterInstall previous, IInterpreterInstall current) { |
| Object[] listeners = fgInterpreterListeners.getListeners(); |
| for (int i = 0; i < listeners.length; i++) { |
| IInterpreterInstallChangedListener listener = (IInterpreterInstallChangedListener) listeners[i]; |
| listener.defaultInterpreterInstallChanged(previous, current); |
| } |
| } |
| |
| /** |
| * Notifies all Interpreter install changed listeners of the given property |
| * change. |
| * |
| * @param event |
| * event describing the change. |
| * |
| */ |
| public static void fireInterpreterChanged(PropertyChangeEvent event) { |
| Object[] listeners = fgInterpreterListeners.getListeners(); |
| for (int i = 0; i < listeners.length; i++) { |
| IInterpreterInstallChangedListener listener = (IInterpreterInstallChangedListener) listeners[i]; |
| listener.interpreterChanged(event); |
| } |
| } |
| |
| /** |
| * Notifies all Interpreter install changed listeners of the Interpreter |
| * addition |
| * |
| * @param Interpreter |
| * the Interpreter that has been added |
| * |
| */ |
| public static void fireInterpreterAdded(IInterpreterInstall Interpreter) { |
| if (!fgInitializingInterpreters) { |
| Object[] listeners = fgInterpreterListeners.getListeners(); |
| for (int i = 0; i < listeners.length; i++) { |
| IInterpreterInstallChangedListener listener = (IInterpreterInstallChangedListener) listeners[i]; |
| listener.interpreterAdded(Interpreter); |
| } |
| } |
| } |
| |
| /** |
| * Notifies all Interpreter install changed listeners of the Interpreter |
| * removal |
| * |
| * @param Interpreter |
| * the Interpreter that has been removed |
| * |
| */ |
| public static void fireInterpreterRemoved(IInterpreterInstall Interpreter) { |
| Object[] listeners = fgInterpreterListeners.getListeners(); |
| for (int i = 0; i < listeners.length; i++) { |
| IInterpreterInstallChangedListener listener = (IInterpreterInstallChangedListener) listeners[i]; |
| listener.interpreterRemoved(Interpreter); |
| } |
| } |
| |
| /** |
| * Returns the preference store for the launching plug-in. |
| * |
| * @return the preference store for the launching plug-in |
| * @since 5.0 return type changed to {@link IEclipsePreferences} |
| */ |
| public static IEclipsePreferences getPreferences() { |
| return InstanceScope.INSTANCE.getNode(DLTKLaunchingPlugin.PLUGIN_ID); |
| } |
| |
| /** |
| * Saves the preferences for the launching plug-in. |
| * |
| * |
| */ |
| public static void savePreferences() { |
| try { |
| getPreferences().flush(); |
| } catch (BackingStoreException e) { |
| DLTKLaunchingPlugin.log(e); |
| } |
| } |
| |
| /** |
| * Registers the given resolver for the specified container. |
| * |
| * @param resolver |
| * runtime buildpath entry resolver |
| * @param containerIdentifier |
| * identifier of the buildpath container to register for |
| * |
| */ |
| public static void addContainerResolver( |
| IRuntimeBuildpathEntryResolver resolver, |
| String containerIdentifier) { |
| Map<String, IRuntimeBuildpathEntryResolver> map = getContainerResolvers(); |
| map.put(containerIdentifier, resolver); |
| } |
| |
| /** |
| * Returns all registered container resolvers. |
| */ |
| private static Map<String, IRuntimeBuildpathEntryResolver> getContainerResolvers() { |
| if (fgContainerResolvers == null) { |
| initializeResolvers(); |
| } |
| return fgContainerResolvers; |
| } |
| |
| private static void initializeResolvers() { |
| IExtensionPoint point = Platform.getExtensionRegistry() |
| .getExtensionPoint(DLTKLaunchingPlugin.PLUGIN_ID, |
| EXTENSION_POINT_RUNTIME_BUILDPATH_ENTRY_RESOLVERS); |
| IConfigurationElement[] extensions = point.getConfigurationElements(); |
| fgContainerResolvers = new HashMap<>(extensions.length); |
| fgRuntimeBuildpathEntryResolvers = new HashMap<>(extensions.length); |
| for (int i = 0; i < extensions.length; i++) { |
| RuntimeBuildpathEntryResolver res = new RuntimeBuildpathEntryResolver( |
| extensions[i]); |
| String container = res.getContainerId(); |
| String entryId = res.getRuntimeBuildpathEntryId(); |
| if (container != null) { |
| fgContainerResolvers.put(container, res); |
| } |
| if (entryId != null) { |
| fgRuntimeBuildpathEntryResolvers.put(entryId, res); |
| } |
| } |
| } |
| |
| /** |
| * Returns all registered buildpath providers. |
| */ |
| private static Map<String, IRuntimeBuildpathProvider> getBuildpathProviders() { |
| if (fgPathProviders == null) { |
| initializeProviders(); |
| } |
| return fgPathProviders; |
| } |
| |
| private static void initializeProviders() { |
| IExtensionPoint point = Platform.getExtensionRegistry() |
| .getExtensionPoint(DLTKLaunchingPlugin.PLUGIN_ID, |
| EXTENSION_POINT_RUNTIME_BUILDPATH_PROVIDERS); |
| IConfigurationElement[] extensions = point.getConfigurationElements(); |
| fgPathProviders = new HashMap<>(extensions.length); |
| for (int i = 0; i < extensions.length; i++) { |
| RuntimeBuildpathProvider res = new RuntimeBuildpathProvider( |
| extensions[i]); |
| fgPathProviders.put(res.getIdentifier(), res); |
| } |
| } |
| |
| /** |
| * Returns the resolver registered for the given container id, or |
| * <code>null</code> if none. |
| * |
| * @param containerId |
| * the container to determine the resolver for |
| * @return the resolver registered for the given container id, or |
| * <code>null</code> if none |
| */ |
| private static IRuntimeBuildpathEntryResolver2 getContainerResolver( |
| String containerId) { |
| return (IRuntimeBuildpathEntryResolver2) getContainerResolvers() |
| .get(containerId); |
| } |
| |
| /** |
| * Returns a collection of paths that should be appended to the given |
| * project's library path when launched. Entries are searched for on the |
| * project's build path as extra buildpath attributes. Each entry represents |
| * an absolute path in the local file system. |
| * |
| * @param project |
| * the project to compute the <code>java.library.path</code> for |
| * @param requiredProjects |
| * whether to consider entries in required projects |
| * @return a collection of paths representing entries that should be |
| * appended to the given project's <code>java.library.path</code> |
| * @throws CoreException |
| * if unable to compute the Script library path |
| * |
| * @see org.eclipse.dltk.core.IBuildpathAttribute |
| * @see ScriptRuntime#BUILDPATH_ATTR_LIBRARY_PATH_ENTRY |
| */ |
| public static String[] computeScriptLibraryPath(IScriptProject project, |
| boolean requiredProjects) throws CoreException { |
| Set<IScriptProject> visited = new HashSet<>(); |
| List<String> entries = new ArrayList<>(); |
| gatherScriptLibraryPathEntries(project, requiredProjects, visited, |
| entries); |
| List<String> resolved = new ArrayList<>(entries.size()); |
| IStringVariableManager manager = VariablesPlugin.getDefault() |
| .getStringVariableManager(); |
| IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); |
| for (String entry : entries) { |
| String resolvedEntry = manager.performStringSubstitution(entry); |
| IPath path = new Path(resolvedEntry); |
| if (path.isAbsolute()) { |
| File file = path.toFile(); |
| resolved.add(file.getAbsolutePath()); |
| } else { |
| IResource resource = root.findMember(path); |
| if (resource != null) { |
| IPath location = resource.getLocation(); |
| if (location != null) { |
| resolved.add(location.toFile().getAbsolutePath()); |
| } |
| } |
| } |
| } |
| return resolved.toArray(new String[resolved.size()]); |
| } |
| |
| /** |
| * Gathers all Script library entries for the given project and optionally |
| * its required projects. |
| * |
| * @param project |
| * project to gather entries for |
| * @param requiredProjects |
| * whether to consider required projects |
| * @param visited |
| * projects already considered |
| * @param entries |
| * collection to add library entries to |
| * @throws CoreException |
| * if unable to gather buildpath entries |
| * |
| */ |
| private static void gatherScriptLibraryPathEntries(IScriptProject project, |
| boolean requiredProjects, Set<IScriptProject> visited, |
| List<String> entries) throws CoreException { |
| if (visited.contains(project)) { |
| return; |
| } |
| visited.add(project); |
| IBuildpathEntry[] rawBuildpath = project.getRawBuildpath(); |
| IBuildpathEntry[] required = processScriptLibraryPathEntries(project, |
| requiredProjects, rawBuildpath, entries); |
| if (required != null) { |
| IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); |
| for (int i = 0; i < required.length; i++) { |
| IBuildpathEntry entry = required[i]; |
| String projectName = entry.getPath().segment(0); |
| IProject p = root.getProject(projectName); |
| if (p.exists()) { |
| IScriptProject requiredProject = DLTKCore.create(p); |
| if (requiredProject != null) { |
| gatherScriptLibraryPathEntries(requiredProject, |
| requiredProjects, visited, entries); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Adds all library path extra buildpath entry values to the given entries |
| * collection specified on the given project's buildpath, and returns a |
| * collection of required projects, or <code>null</code>. |
| * |
| * @param project |
| * project being processed |
| * @param collectRequired |
| * whether to collect required projects |
| * @param buildpathEntries |
| * the project's raw buildpath |
| * @param entries |
| * collection to add script library path entries to |
| * @return required project buildpath entries or <code>null</code> |
| * @throws CoreException |
| * |
| */ |
| private static IBuildpathEntry[] processScriptLibraryPathEntries( |
| IScriptProject project, boolean collectRequired, |
| IBuildpathEntry[] buildpathEntries, List<String> entries) |
| throws CoreException { |
| List<IBuildpathEntry> req = null; |
| for (int i = 0; i < buildpathEntries.length; i++) { |
| IBuildpathEntry entry = buildpathEntries[i]; |
| IBuildpathAttribute[] extraAttributes = entry.getExtraAttributes(); |
| for (int j = 0; j < extraAttributes.length; j++) { |
| String[] paths = getLibraryPaths(extraAttributes[j]); |
| if (paths != null) { |
| for (int k = 0; k < paths.length; k++) { |
| entries.add(paths[k]); |
| } |
| } |
| } |
| if (entry.getEntryKind() == IBuildpathEntry.BPE_CONTAINER) { |
| IBuildpathContainer container = DLTKCore |
| .getBuildpathContainer(entry.getPath(), project); |
| if (container != null) { |
| IBuildpathEntry[] requiredProjects = processScriptLibraryPathEntries( |
| project, collectRequired, |
| container.getBuildpathEntries(), entries); |
| if (requiredProjects != null) { |
| if (req == null) { |
| req = new ArrayList<>(); |
| } |
| for (int j = 0; j < requiredProjects.length; j++) { |
| req.add(requiredProjects[j]); |
| } |
| } |
| } |
| } else if (collectRequired |
| && entry.getEntryKind() == IBuildpathEntry.BPE_PROJECT) { |
| if (req == null) { |
| req = new ArrayList<>(); |
| } |
| req.add(entry); |
| } |
| } |
| if (req != null) { |
| return req.toArray(new IBuildpathEntry[req.size()]); |
| } |
| return null; |
| } |
| |
| /** |
| * Creates a new buildpath attribute referencing a list of shared libraries |
| * that should appear on the <code>-Djava.library.path</code> system |
| * property at runtime for an associated {@link IBuildpathEntry}. |
| * <p> |
| * The factory methods <code>newLibraryPathsAttribute(String[])</code> and |
| * <code>getLibraryPaths(IBuildpathAttribute)</code> should be used to |
| * encode and decode the attribute value. |
| * </p> |
| * |
| * @param paths |
| * an array of strings representing paths of shared libraries. |
| * Each string is used to create an <code>IPath</code> using the |
| * constructor <code>Path(String)</code>, and may contain |
| * <code>IStringVariable</code>'s. Variable substitution is |
| * performed on each string before a path is constructed from a |
| * string. |
| * @return a buildpath attribute with the name |
| * <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code> and an value |
| * encoded to the specified paths. |
| * |
| */ |
| public static IBuildpathAttribute newLibraryPathsAttribute(String[] paths) { |
| StringBuffer value = new StringBuffer(); |
| for (int i = 0; i < paths.length; i++) { |
| value.append(paths[i]); |
| if (i < (paths.length - 1)) { |
| value.append("|"); //$NON-NLS-1$ |
| } |
| } |
| return DLTKCore.newBuildpathAttribute(BUILDPATH_ATTR_LIBRARY_PATH_ENTRY, |
| value.toString()); |
| } |
| |
| /** |
| * Returns an array of strings referencing shared libraries that should |
| * appear on the <code>-Djava.library.path</code> system property at runtime |
| * for an associated {@link IBuildpathEntry}, or <code>null</code> if the |
| * given attribute is not a <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code>. |
| * Each string is used to create an <code>IPath</code> using the constructor |
| * <code>Path(String)</code>, and may contain <code>IStringVariable</code> |
| * 's. |
| * <p> |
| * The factory methods <code>newLibraryPathsAttribute(String[])</code> and |
| * <code>getLibraryPaths(IBuildpathAttribute)</code> should be used to |
| * encode and decode the attribute value. |
| * </p> |
| * |
| * @param attribute |
| * a <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code> buildpath |
| * attribute |
| * @return an array of strings referencing shared libraries that should |
| * appear on the <code>-Djava.library.path</code> system property at |
| * runtime for an associated {@link IBuildpathEntry}, or |
| * <code>null</code> if the given attribute is not a |
| * <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code>. Each string is |
| * used to create an <code>IPath</code> using the constructor |
| * <code>Path(String)</code>, and may contain |
| * <code>IStringVariable</code>'s. |
| * |
| */ |
| public static String[] getLibraryPaths(IBuildpathAttribute attribute) { |
| if (BUILDPATH_ATTR_LIBRARY_PATH_ENTRY.equals(attribute.getName())) { |
| String value = attribute.getValue(); |
| return value.split("\\|"); //$NON-NLS-1$ |
| } |
| return null; |
| } |
| |
| /** |
| * Loads contributed interpreter installs |
| * |
| */ |
| private static void addInterpreterExtensions( |
| InterpreterDefinitionsContainer InterpreterDefs) { |
| IExtensionPoint extensionPoint = Platform.getExtensionRegistry() |
| .getExtensionPoint(DLTKLaunchingPlugin.PLUGIN_ID, |
| ScriptRuntime.EXTENSION_POINT_INTERPRETER_INSTALLS); |
| IConfigurationElement[] configs = extensionPoint |
| .getConfigurationElements(); |
| for (int i = 0; i < configs.length; i++) { |
| IConfigurationElement element = configs[i]; |
| try { |
| if ("interpreterInstall".equals(element.getName())) { //$NON-NLS-1$ |
| String InterpreterType = element |
| .getAttribute("interpreterInstallType"); //$NON-NLS-1$ |
| if (InterpreterType == null) { |
| abort(MessageFormat.format( |
| "Missing required interpreterInstallType attribute for interpreterInstall contributed by {0}", //$NON-NLS-1$ |
| element.getContributor().getName()), null); |
| } |
| String id = element.getAttribute("id"); //$NON-NLS-1$ |
| if (id == null) { |
| abort(MessageFormat.format( |
| "Missing required id attribute for interpreterInstall contributed by {0}", //$NON-NLS-1$ |
| element.getContributor().getName()), null); |
| } |
| IInterpreterInstallType installType = getInterpreterInstallType( |
| InterpreterType); |
| if (installType == null) { |
| throw abort(MessageFormat.format( |
| "InterpreterInstall {0} contributed by {1} references undefined Interpreter install type {2}", //$NON-NLS-1$ |
| id, element.getContributor().getName(), |
| InterpreterType), null); |
| } |
| IInterpreterInstall install = installType |
| .findInterpreterInstall(id); |
| if (install == null) { |
| // only load/create if first time we've seen this |
| // Interpreter install |
| String name = element.getAttribute("name"); //$NON-NLS-1$ |
| if (name == null) { |
| abort(MessageFormat.format( |
| "interpreterInstall {0} contributed by {1} missing required attribute name", //$NON-NLS-1$ |
| id, element.getContributor().getName()), |
| null); |
| } |
| final String home = element.getAttribute("home"); //$NON-NLS-1$ |
| if (home == null) { |
| abort(MessageFormat.format( |
| "interpreterInstall {0} contributed by {1} missing required attribute home", //$NON-NLS-1$ |
| id, element.getContributor().getName()), |
| null); |
| } |
| String InterpreterArgs = element |
| .getAttribute("interpreterArgs"); //$NON-NLS-1$ |
| InterpreterStandin standin = new InterpreterStandin( |
| installType, id); |
| standin.setName(name); |
| |
| // Only local installs can be contributed, so |
| // use local environment |
| final IEnvironment localEnv = EnvironmentManager |
| .getLocalEnvironment(); |
| |
| IFileHandle homeFile = localEnv |
| .getFile(toPath(element, substitute(home))); |
| if (homeFile.exists()) { |
| // adjust for relative path names |
| homeFile = localEnv.getFile( |
| new Path(homeFile.getCanonicalPath())); |
| } |
| IStatus status = installType.validateInstallLocation( |
| homeFile, standin.getEnvironmentVariables(), |
| standin.getLibraryLocations(), |
| new NullProgressMonitor()); |
| if (!status.isOK()) { |
| abort(MessageFormat.format( |
| "Illegal install location {0} for interpreterInstall {1} contributed by {2}: {3}", //$NON-NLS-1$ |
| home, id, |
| element.getContributor().getName(), |
| status.getMessage()), null); |
| } |
| standin.setInstallLocation(homeFile); |
| |
| if (InterpreterArgs != null) { |
| standin.setInterpreterArgs(InterpreterArgs); |
| } |
| IConfigurationElement[] libraries = element |
| .getChildren("library"); //$NON-NLS-1$ |
| LibraryLocation[] locations = null; |
| if (libraries.length > 0) { |
| locations = new LibraryLocation[libraries.length]; |
| for (int j = 0; j < libraries.length; j++) { |
| IConfigurationElement library = libraries[j]; |
| String libPathStr = library |
| .getAttribute("path"); //$NON-NLS-1$ |
| if (libPathStr == null) { |
| abort(MessageFormat.format( |
| "library for interpreterInstall {0} contributed by {1} missing required attribute libPath", //$NON-NLS-1$ |
| id, |
| element.getContributor().getName()), |
| null); |
| } |
| |
| locations[j] = new LibraryLocation( |
| homeFile.getFullPath().append( |
| substitute(libPathStr))); |
| } |
| } |
| standin.setLibraryLocations(locations); |
| InterpreterDefs.addInterpreter(standin, true); |
| } |
| fgContributedInterpreters.add(id); |
| } else { |
| abort(MessageFormat.format( |
| "Illegal element {0} in InterpreterInstalls extension contributed by {1}", //$NON-NLS-1$ |
| element.getName(), |
| element.getContributor().getName()), null); |
| } |
| } catch (CoreException e) { |
| DLTKLaunchingPlugin.log(e); |
| } |
| } |
| } |
| |
| private static IPath toPath(IConfigurationElement element, String path) |
| throws CoreException { |
| String bundleId = element.getAttribute("bundle"); |
| if (bundleId != null) { |
| if (bundleId.equals(".")) { |
| bundleId = element.getContributor().getName(); |
| } |
| final Bundle bundle = Platform.getBundle(bundleId); |
| if (bundle != null) { |
| try { |
| final File bundleFile = FileLocator.getBundleFile(bundle); |
| final IPath bundlePath = new Path( |
| bundleFile.getCanonicalPath()); |
| return bundlePath.append(new Path(path)); |
| } catch (IOException e) { |
| abort(NLS.bind("Error resolving {0} bundle location", |
| bundleId), e); |
| } |
| } |
| } |
| return new Path(path); |
| } |
| |
| private static InterpreterStandin[] detectInterpreterInstall( |
| String natureId, List<IInterpreterInstallType> interpTypes) { |
| // Try to create a interpreter install using the install location |
| for (IInterpreterInstallType interpType : interpTypes) { |
| final IFileHandle[] detectedLocations = interpType |
| .detectInstallLocations(); |
| if (detectedLocations != null && detectedLocations.length != 0) { |
| // Make sure the interpreter id is unique |
| long unique = System.currentTimeMillis(); |
| final InterpreterStandin[] result = new InterpreterStandin[detectedLocations.length]; |
| for (int j = 0; j < detectedLocations.length; ++j) { |
| while (interpType.findInterpreterInstall( |
| String.valueOf(unique)) != null) { |
| unique++; |
| } |
| final IFileHandle location = detectedLocations[j]; |
| // Create a standin for the detected interpreter |
| final InterpreterStandin detected = new InterpreterStandin( |
| interpType, String.valueOf(unique++)); |
| detected.setInstallLocation(location); |
| detected.setName(interpType |
| .generateDetectedInterpreterName(location)); |
| result[j] = detected; |
| } |
| return result; |
| } |
| } |
| return null; |
| } |
| |
| private static Map<String, List<IInterpreterInstallType>> getInterpreterTypesByNature() { |
| Map<String, List<IInterpreterInstallType>> result = new HashMap<>(); |
| for (IInterpreterInstallType type : fgInterpreterTypes) { |
| String natureId = type.getNatureId(); |
| if (!result.containsKey(natureId)) { |
| result.put(natureId, new ArrayList<IInterpreterInstallType>()); |
| } |
| result.get(natureId).add(type); |
| } |
| return result; |
| } |
| |
| private static Map<String, List<IInterpreterInstall>> getValidInterpretersByNature( |
| List<IInterpreterInstall> validInterpreters) { |
| Map<String, List<IInterpreterInstall>> result = new HashMap<>(); |
| for (IInterpreterInstall install : validInterpreters) { |
| String natureId = install.getNatureId(); |
| if (!result.containsKey(natureId)) { |
| result.put(natureId, new ArrayList<IInterpreterInstall>()); |
| } |
| result.get(natureId).add(install); |
| } |
| return result; |
| } |
| |
| /** |
| * Perform Interpreter type and Interpreter install initialization. Does not |
| * hold locks while performing change notification. |
| * |
| * |
| */ |
| private static void initializeInterpreters() { |
| InterpreterDefinitionsContainer defs = null; |
| boolean setPref = false; |
| synchronized (fgInterpreterLock) { |
| if (fgInterpreterTypes == null) { |
| try { |
| fgInitializingInterpreters = true; |
| // 1. load Interpreter type extensions |
| initializeInterpreterTypeExtensions(); |
| defs = new InterpreterDefinitionsContainer(); |
| |
| // 2. add persisted Interpreters |
| setPref = addPersistedInterpreters(defs); |
| |
| // 3. if there are none, detect interpreters |
| Map<String, List<IInterpreterInstallType>> typesByNature = getInterpreterTypesByNature(); |
| Map<String, List<IInterpreterInstall>> interpsByNature = getValidInterpretersByNature( |
| defs.getValidInterpreterList()); |
| for (String natureId : typesByNature.keySet()) { |
| if (!interpsByNature.containsKey(natureId) |
| || interpsByNature.get(natureId).isEmpty()) { |
| // calling out to detectInterpreterInstall(nature) |
| // could allow clients to change |
| // Interpreter settings (i.e. call back into change |
| // Interpreter settings). |
| InterpreterListener listener = new InterpreterListener(); |
| addInterpreterInstallChangedListener(listener); |
| setPref = true; |
| InterpreterStandin[] interp = detectInterpreterInstall( |
| natureId, typesByNature.get(natureId)); |
| removeInterpreterInstallChangedListener(listener); |
| if (!listener.isChanged()) { |
| if (interp != null) { |
| for (InterpreterStandin standin : interp) { |
| defs.addInterpreter(standin); |
| } |
| defs.setDefaultInterpreterInstallCompositeID( |
| new DefaultInterpreterEntry( |
| natureId, |
| interp[0] |
| .getEnvironmentId()), |
| getCompositeIdFromInterpreter( |
| interp[0])); |
| } |
| } else { |
| // interpreters were changed - reflect current |
| // settings |
| addPersistedInterpreters(defs); |
| // copy default interpreters |
| for (Map.Entry<DefaultInterpreterEntry, String> entry : fgDefaultInterpreterId |
| .entrySet()) { |
| defs.setDefaultInterpreterInstallCompositeID( |
| entry.getKey(), entry.getValue()); |
| } |
| } |
| } |
| } |
| |
| // 4. load contributed Interpreter installs |
| addInterpreterExtensions(defs); |
| |
| // 5. verify default interpreters is valid |
| DefaultInterpreterEntry[] natures = defs |
| .getInterpreterNatures(); |
| for (int i = 0; i < natures.length; i++) { |
| String defId = defs |
| .getDefaultInterpreterInstallCompositeID( |
| natures[i]); |
| boolean validDef = false; |
| if (defId != null) { |
| for (IInterpreterInstall iterpreter : defs |
| .getValidInterpreterList()) { |
| if (getCompositeIdFromInterpreter(iterpreter) |
| .equals(defId)) { |
| validDef = true; |
| break; |
| } |
| } |
| } |
| |
| if (!validDef) { |
| // use the first as the default |
| setPref = true; |
| List<IInterpreterInstall> list = defs |
| .getValidInterpreterList(natures[i]); |
| if (!list.isEmpty()) { |
| IInterpreterInstall Interpreter = list.get(0); |
| defs.setDefaultInterpreterInstallCompositeID( |
| natures[i], |
| getCompositeIdFromInterpreter( |
| Interpreter)); |
| } |
| } |
| |
| String defInstCID = defs |
| .getDefaultInterpreterInstallCompositeID( |
| natures[i]); |
| fgDefaultInterpreterId.put(natures[i], defInstCID); |
| String defIntCTypeID = defs |
| .getDefaultInterpreterInstallConnectorTypeID( |
| natures[i]); |
| fgDefaultInterpreterConnectorId.put(natures[i], |
| defIntCTypeID); |
| } |
| // Create the underlying interpreters for each valid |
| // Interpreter |
| List<IInterpreterInstall> InterpreterList = defs |
| .getValidInterpreterList(); |
| Iterator<IInterpreterInstall> InterpreterListIterator = InterpreterList |
| .iterator(); |
| while (InterpreterListIterator.hasNext()) { |
| InterpreterStandin InterpreterStandin = (InterpreterStandin) InterpreterListIterator |
| .next(); |
| InterpreterStandin.convertToRealInterpreter(); |
| } |
| |
| } finally { |
| fgInitializingInterpreters = false; |
| } |
| } |
| } |
| if (defs != null) { |
| // notify of initial Interpreters for backwards compatibility |
| IInterpreterInstallType[] installTypes = getInterpreterInstallTypes(); |
| for (int i = 0; i < installTypes.length; i++) { |
| IInterpreterInstallType type = installTypes[i]; |
| IInterpreterInstall[] installs = type.getInterpreterInstalls(); |
| if (installs != null) { |
| for (int j = 0; j < installs.length; j++) { |
| fireInterpreterAdded(installs[j]); |
| } |
| } |
| } |
| |
| // save settings if required |
| if (setPref) { |
| try { |
| String xml = defs.getAsXML(); |
| getPreferences().put(PREF_INTERPRETER_XML, xml); |
| } catch (ParserConfigurationException e) { |
| DLTKLaunchingPlugin.log(e); |
| } catch (IOException e) { |
| DLTKLaunchingPlugin.log(e); |
| } catch (TransformerException e) { |
| DLTKLaunchingPlugin.log(e); |
| } |
| |
| } |
| |
| } |
| } |
| |
| /** |
| * Returns a new runtime buildpath entry containing the default buildpath |
| * for the specified script project. |
| * |
| * @param project |
| * project |
| * @return runtime buildpath entry |
| * |
| */ |
| public static IRuntimeBuildpathEntry newDefaultProjectBuildpathEntry( |
| IScriptProject project) { |
| return new DefaultProjectBuildpathEntry(project); |
| } |
| |
| /** |
| * Returns a new runtime buildpath entry for the given project. |
| * |
| * @param project |
| * Script project |
| * @return runtime buildpath entry |
| * |
| */ |
| public static IRuntimeBuildpathEntry newProjectRuntimeBuildpathEntry( |
| IScriptProject project) { |
| IBuildpathEntry cpe = DLTKCore |
| .newProjectEntry(project.getProject().getFullPath()); |
| return newRuntimeBuildpathEntry(cpe); |
| } |
| |
| /** |
| * Returns a new runtime buildpath entry for the given archive. |
| * |
| * @param resource |
| * archive resource |
| * @return runtime buildpath entry |
| * |
| */ |
| public static IRuntimeBuildpathEntry newArchiveRuntimeBuildpathEntry( |
| IResource resource) { |
| IBuildpathEntry cpe = DLTKCore.newLibraryEntry(resource.getFullPath()); |
| return newRuntimeBuildpathEntry(cpe); |
| } |
| |
| /** |
| * Returns a new runtime buildpath entry for the given archive (possibly |
| * external). |
| * |
| * @param path |
| * absolute path to an archive |
| * @return runtime buildpath entry |
| * |
| */ |
| public static IRuntimeBuildpathEntry newArchiveRuntimeBuildpathEntry( |
| IPath path) { |
| IBuildpathEntry cpe = DLTKCore.newLibraryEntry(path); |
| return newRuntimeBuildpathEntry(cpe); |
| } |
| |
| /** |
| * Returns a runtime buildpath entry for the given container path with the |
| * given buildpath property. |
| * |
| * @param path |
| * container path |
| * @param buildpathProperty |
| * the type of entry - one of <code>USER_CLASSES</code>, or |
| * <code>STANDARD_CLASSES</code> |
| * @return runtime buildpath entry |
| * @exception CoreException |
| * if unable to construct a runtime buildpath entry |
| * |
| */ |
| public static IRuntimeBuildpathEntry newRuntimeContainerBuildpathEntry( |
| IPath path, int buildpathProperty) throws CoreException { |
| return newRuntimeContainerBuildpathEntry(path, buildpathProperty, null); |
| } |
| |
| /** |
| * Returns a runtime buildpath entry for the given container path with the |
| * given buildpath property to be resolved in the context of the given |
| * Script project. |
| * |
| * @param path |
| * container path |
| * @param buildpathProperty |
| * the type of entry - one of <code>USER_CLASSES</code>, or |
| * <code>STANDARD_CLASSES</code> |
| * @param project |
| * Script project context used for resolution, or |
| * <code>null</code> if to be resolved in the context of the |
| * launch configuration this entry is referenced in |
| * @return runtime buildpath entry |
| * @exception CoreException |
| * if unable to construct a runtime buildpath entry |
| */ |
| public static IRuntimeBuildpathEntry newRuntimeContainerBuildpathEntry( |
| IPath path, int buildpathProperty, IScriptProject project) |
| throws CoreException { |
| IBuildpathEntry cpe = DLTKCore.newContainerEntry(path); |
| RuntimeBuildpathEntry entry = new RuntimeBuildpathEntry(cpe, |
| buildpathProperty); |
| entry.setScriptProject(project); |
| return entry; |
| } |
| |
| /** |
| * Returns a runtime buildpath entry constructed from the given memento. |
| * |
| * @param memento |
| * a memento for a runtime buildpath entry |
| * @return runtime buildpath entry |
| * @exception CoreException |
| * if unable to construct a runtime buildpath entry |
| */ |
| public static IRuntimeBuildpathEntry newRuntimeBuildpathEntry( |
| String memento) throws CoreException { |
| try { |
| Element root = null; |
| DocumentBuilder parser = DLTKLaunchingPlugin.getParser(); |
| StringReader reader = new StringReader(memento); |
| InputSource source = new InputSource(reader); |
| root = parser.parse(source).getDocumentElement(); |
| |
| String id = root.getAttribute("id"); //$NON-NLS-1$ |
| if (id == null || id.length() == 0) { |
| // assume an old format |
| return new RuntimeBuildpathEntry(root); |
| } |
| // get the extension & create a new one |
| IRuntimeBuildpathEntry2 entry = DLTKLaunchingPlugin.getDefault() |
| .newRuntimeBuildpathEntry(id); |
| NodeList list = root.getChildNodes(); |
| for (int i = 0; i < list.getLength(); i++) { |
| Node node = list.item(i); |
| if (node.getNodeType() == Node.ELEMENT_NODE) { |
| Element element = (Element) node; |
| if ("memento".equals(element.getNodeName())) { //$NON-NLS-1$ |
| entry.initializeFrom(element); |
| } |
| } |
| } |
| return entry; |
| } catch (SAXException e) { |
| abort(LaunchingMessages.ScriptRuntime_31, e); |
| } catch (IOException e) { |
| abort(LaunchingMessages.ScriptRuntime_32, e); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a runtime buildpath entry that corresponds to the given buildpath |
| * entry. The buildpath entry may not be of type <code>CPE_SOURCE</code> or |
| * <code>BPE_CONTAINER</code>. |
| * |
| * @param entry |
| * a buildpath entry |
| * @return runtime buildpath entry |
| */ |
| private static IRuntimeBuildpathEntry newRuntimeBuildpathEntry( |
| IBuildpathEntry entry) { |
| return new RuntimeBuildpathEntry(entry); |
| } |
| |
| /** |
| * Computes and returns the default unresolved runtime buildpath for the |
| * given project. |
| * |
| * @return runtime buildpath entries |
| * @exception CoreException |
| * if unable to compute the runtime buildpath |
| * @see IRuntimeBuildpathEntry |
| * |
| */ |
| public static IRuntimeBuildpathEntry[] computeUnresolvedRuntimeBuildpath( |
| IScriptProject project) throws CoreException { |
| IBuildpathEntry[] entries = project.getRawBuildpath(); |
| List<IRuntimeBuildpathEntry> buildpathEntries = new ArrayList<>(3); |
| for (int i = 0; i < entries.length; i++) { |
| IBuildpathEntry entry = entries[i]; |
| switch (entry.getEntryKind()) { |
| case IBuildpathEntry.BPE_CONTAINER: |
| IBuildpathContainer container = DLTKCore |
| .getBuildpathContainer(entry.getPath(), project); |
| if (container != null) { |
| switch (container.getKind()) { |
| case IBuildpathContainer.K_APPLICATION: |
| // don't look at application entries |
| break; |
| case IBuildpathContainer.K_DEFAULT_SYSTEM: |
| case IBuildpathContainer.K_SYSTEM: |
| buildpathEntries.add(newRuntimeContainerBuildpathEntry( |
| container.getPath(), |
| IRuntimeBuildpathEntry.STANDARD_ENTRY, |
| project)); |
| break; |
| } |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| buildpathEntries.add(newDefaultProjectBuildpathEntry(project)); |
| return buildpathEntries |
| .toArray(new IRuntimeBuildpathEntry[buildpathEntries.size()]); |
| } |
| |
| /** |
| * Returns the buildpath provider for the given launch configuration. |
| * |
| * @param configuration |
| * launch configuration |
| * @return buildpath provider |
| * @exception CoreException |
| * if unable to resolve the path provider |
| */ |
| public static IRuntimeBuildpathProvider getBuildpathProvider( |
| ILaunchConfiguration configuration) throws CoreException { |
| String providerId = configuration.getAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_BUILDPATH_PROVIDER, |
| (String) null); |
| IRuntimeBuildpathProvider provider = null; |
| if (providerId == null) { |
| provider = fgDefaultBuildpathProvider; |
| } else { |
| provider = getBuildpathProviders().get(providerId); |
| if (provider == null) { |
| abort(MessageFormat.format(LaunchingMessages.ScriptRuntime_26, |
| providerId), null); |
| } |
| } |
| return provider; |
| } |
| |
| public static IRuntimeBuildpathProvider getScriptpathProvider( |
| ILaunchConfiguration configuration) throws CoreException { |
| |
| String providerId = configuration.getAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_SOURCEPATH_PROVIDER, |
| (String) null); |
| IRuntimeBuildpathProvider provider = null; |
| if (providerId == null) { |
| provider = fgDefaultSourcepathProvider; |
| } else { |
| provider = getBuildpathProviders().get(providerId); |
| if (provider == null) { |
| abort(MessageFormat.format(LaunchingMessages.ScriptRuntime_27, |
| providerId), null); |
| } |
| } |
| return provider; |
| } |
| |
| /** |
| * Performs default resolution for a container entry. Delegates to the |
| * Script model. |
| */ |
| private static IRuntimeBuildpathEntry[] computeDefaultContainerEntries( |
| IRuntimeBuildpathEntry entry, ILaunchConfiguration config) |
| throws CoreException { |
| IScriptProject project = entry.getScriptProject(); |
| |
| if (project == null) { |
| project = getScriptProject(config); |
| } |
| return computeDefaultContainerEntries(entry, project); |
| } |
| |
| /** |
| * Performs default resolution for a container entry. Delegates to the |
| * Script model. |
| */ |
| private static IRuntimeBuildpathEntry[] computeDefaultContainerEntries( |
| IRuntimeBuildpathEntry entry, IScriptProject project) |
| throws CoreException { |
| if (project == null || entry == null) { |
| // cannot resolve without entry or project context |
| return new IRuntimeBuildpathEntry[0]; |
| } |
| IBuildpathContainer container = DLTKCore |
| .getBuildpathContainer(entry.getPath(), project); |
| if (container == null) { |
| abort(MessageFormat.format( |
| LaunchingMessages.ScriptRuntime_Could_not_resolve_classpath_container___0__1, |
| entry.getPath().toString()), null); |
| // execution will not reach here - exception will be thrown |
| return null; |
| } |
| IBuildpathEntry[] cpes = container.getBuildpathEntries(); |
| int property = -1; |
| switch (container.getKind()) { |
| case IBuildpathContainer.K_APPLICATION: |
| property = IRuntimeBuildpathEntry.USER_ENTRY; |
| break; |
| case IBuildpathContainer.K_DEFAULT_SYSTEM: |
| property = IRuntimeBuildpathEntry.STANDARD_ENTRY; |
| break; |
| case IBuildpathContainer.K_SYSTEM: |
| property = IRuntimeBuildpathEntry.BOOTSTRAP_ENTRY; |
| break; |
| } |
| List<IRuntimeBuildpathEntry> resolved = new ArrayList<>(cpes.length); |
| List<IScriptProject> projects = fgProjects.get(); |
| Integer count = fgEntryCount.get(); |
| if (projects == null) { |
| projects = new ArrayList<>(); |
| fgProjects.set(projects); |
| count = Integer.valueOf(0); |
| } |
| int intCount = count.intValue(); |
| intCount++; |
| fgEntryCount.set(Integer.valueOf(intCount)); |
| try { |
| for (int i = 0; i < cpes.length; i++) { |
| IBuildpathEntry cpe = cpes[i]; |
| if (cpe.getEntryKind() == IBuildpathEntry.BPE_PROJECT) { |
| IProject p = ResourcesPlugin.getWorkspace().getRoot() |
| .getProject(cpe.getPath().segment(0)); |
| IScriptProject jp = DLTKCore.create(p); |
| if (!projects.contains(jp)) { |
| projects.add(jp); |
| IRuntimeBuildpathEntry buildpath = newDefaultProjectBuildpathEntry( |
| jp); |
| IRuntimeBuildpathEntry[] entries = resolveRuntimeBuildpathEntry( |
| buildpath, jp); |
| for (int j = 0; j < entries.length; j++) { |
| IRuntimeBuildpathEntry e = entries[j]; |
| if (!resolved.contains(e)) { |
| resolved.add(entries[j]); |
| } |
| } |
| } |
| } else { |
| IRuntimeBuildpathEntry e = newRuntimeBuildpathEntry(cpe); |
| if (!resolved.contains(e)) { |
| resolved.add(e); |
| } |
| } |
| } |
| } finally { |
| intCount--; |
| if (intCount == 0) { |
| fgProjects.set(null); |
| fgEntryCount.set(null); |
| } else { |
| fgEntryCount.set(Integer.valueOf(intCount)); |
| } |
| } |
| // set buildpath property |
| IRuntimeBuildpathEntry[] result = new IRuntimeBuildpathEntry[resolved |
| .size()]; |
| for (int i = 0; i < result.length; i++) { |
| result[i] = resolved.get(i); |
| result[i].setBuildpathProperty(property); |
| } |
| return result; |
| } |
| |
| /** |
| * Returns resolved entries for the given entry in the context of the given |
| * launch configuration. If the entry is of kind <code>CONTAINER</code>, |
| * container resolvers are consulted. Otherwise, the given entry is |
| * returned. |
| * <p> |
| * If the given entry is a container, and a resolver is not registered, |
| * resolved runtime buildpath entries are calculated from the associated |
| * container buildpath entries, in the context of the project associated |
| * with the given launch configuration. |
| * </p> |
| * |
| * @param entry |
| * runtime classpath entry |
| * @param configuration |
| * launch configuration |
| * @return resolved runtime classpath entry |
| * @exception CoreException |
| * if unable to resolve |
| * @see IRuntimeBuildpathEntryResolver |
| * |
| */ |
| public static IRuntimeBuildpathEntry[] resolveRuntimeBuildpathEntry( |
| IRuntimeBuildpathEntry entry, ILaunchConfiguration configuration) |
| throws CoreException { |
| switch (entry.getType()) { |
| case IRuntimeBuildpathEntry.PROJECT: |
| // if the project has multiple output locations, they must be |
| // returned |
| IResource resource = entry.getResource(); |
| if (resource instanceof IProject) { |
| IProject p = (IProject) resource; |
| IScriptProject project = DLTKCore.create(p); |
| if (project == null || !p.isOpen() || !project.exists()) { |
| return new IRuntimeBuildpathEntry[0]; |
| } |
| } else { |
| abort(MessageFormat.format( |
| LaunchingMessages.ScriptRuntime_Buildpath_references_non_existant_project___0__3, |
| entry.getPath().lastSegment()), null); |
| } |
| break; |
| case IRuntimeBuildpathEntry.CONTAINER: |
| IRuntimeBuildpathEntryResolver resolver = getContainerResolver( |
| entry.getContainerName()); |
| if (resolver == null) { |
| return computeDefaultContainerEntries(entry, configuration); |
| } |
| return resolver.resolveRuntimeBuildpathEntry(entry, configuration); |
| case IRuntimeBuildpathEntry.ARCHIVE: |
| // verify the archive exists |
| String location = entry.getLocation(); |
| if (location == null) { |
| abort(MessageFormat.format( |
| LaunchingMessages.ScriptRuntime_Buildpath_references_non_existant_archive___0__4, |
| entry.getPath().toString()), null); |
| } |
| IFileHandle fileHandle; |
| IPath path = entry.getPath(); |
| if (EnvironmentPathUtils.isFull(path)) |
| fileHandle = EnvironmentPathUtils.getFile(path); |
| else |
| fileHandle = LocalEnvironment.getInstance().getFile(path); |
| if (fileHandle == null || !fileHandle.exists()) { |
| abort(MessageFormat.format( |
| LaunchingMessages.ScriptRuntime_Buildpath_references_non_existant_archive___0__4, |
| entry.getPath().toString()), null); |
| } |
| break; |
| case IRuntimeBuildpathEntry.OTHER: |
| resolver = getContributedResolver( |
| ((IRuntimeBuildpathEntry2) entry).getTypeId()); |
| return resolver.resolveRuntimeBuildpathEntry(entry, configuration); |
| default: |
| break; |
| } |
| return new IRuntimeBuildpathEntry[] { entry }; |
| } |
| |
| /** |
| * Returns resolved entries for the given entry in the context of the given |
| * script project. If the entry is of kind <code>CONTAINER</code>, container |
| * resolvers are consulted. |
| * <p> |
| * If the given entry is a container, and a resolver is not registered, |
| * resolved runtime classpath entries are calculated from the associated |
| * container classpath entries, in the context of the given project. |
| * </p> |
| * |
| * @param entry |
| * runtime classpath entry |
| * @param project |
| * Script project context |
| * @return resolved runtime classpath entry |
| * @exception CoreException |
| * if unable to resolve |
| * @see IRuntimeBuildpathEntryResolver |
| * |
| */ |
| public static IRuntimeBuildpathEntry[] resolveRuntimeBuildpathEntry( |
| IRuntimeBuildpathEntry entry, IScriptProject project) |
| throws CoreException { |
| switch (entry.getType()) { |
| case IRuntimeBuildpathEntry.CONTAINER: |
| IRuntimeBuildpathEntryResolver resolver = getContainerResolver( |
| entry.getContainerName()); |
| if (resolver == null) { |
| return computeDefaultContainerEntries(entry, project); |
| } |
| return resolver.resolveRuntimeBuildpathEntry(entry, project); |
| case IRuntimeBuildpathEntry.OTHER: |
| resolver = getContributedResolver( |
| ((IRuntimeBuildpathEntry2) entry).getTypeId()); |
| return resolver.resolveRuntimeBuildpathEntry(entry, project); |
| default: |
| break; |
| } |
| return new IRuntimeBuildpathEntry[] { entry }; |
| } |
| |
| /** |
| * Computes and returns the unresolved build path for the given launch |
| * configuration. Variable and container entries are unresolved. |
| * |
| * @param configuration |
| * launch configuration |
| * @return unresolved runtime buildpath entries |
| * @exception CoreException |
| * if unable to compute the buildpath |
| */ |
| public static IRuntimeBuildpathEntry[] computeUnresolvedRuntimeBuildpath( |
| ILaunchConfiguration configuration) throws CoreException { |
| return getBuildpathProvider(configuration) |
| .computeUnresolvedBuildpath(configuration); |
| } |
| |
| /** |
| * Resolves the given buildpath, returning the resolved buildpath in the |
| * context of the given launch configuration. |
| * |
| * @param entries |
| * unresolved buildpath |
| * @param configuration |
| * launch configuration |
| * @return resolved runtime buildpath entries |
| * @exception CoreException |
| * if unable to compute the buildpath |
| */ |
| public static IRuntimeBuildpathEntry[] resolveRuntimeBuildpath( |
| IRuntimeBuildpathEntry[] entries, |
| ILaunchConfiguration configuration) throws CoreException { |
| return getBuildpathProvider(configuration).resolveBuildpath(entries, |
| configuration); |
| } |
| |
| /** |
| * Returns all registered runtime buildpath entry resolvers. |
| */ |
| private static Map<String, IRuntimeBuildpathEntryResolver> getEntryResolvers() { |
| if (fgRuntimeBuildpathEntryResolvers == null) { |
| initializeResolvers(); |
| } |
| return fgRuntimeBuildpathEntryResolvers; |
| } |
| |
| /** |
| * Returns the resolver registered for the given contributed buildpath entry |
| * type. |
| * |
| * @param typeId |
| * the id of the contributed buildpath entry |
| * @return the resolver registered for the given buildpath entry |
| */ |
| private static IRuntimeBuildpathEntryResolver getContributedResolver( |
| String typeId) { |
| IRuntimeBuildpathEntryResolver resolver = getEntryResolvers() |
| .get(typeId); |
| if (resolver == null) { |
| return new DefaultEntryResolver(); |
| } |
| return resolver; |
| } |
| |
| /** |
| * Computes the default application buildpath entries for the given project. |
| * |
| * @param jproject |
| * The project to compute the buildpath for |
| * @return The computed buildpath. May be empty, but not null. |
| * @throws CoreException |
| * if unable to compute the default buildpath |
| */ |
| public static String[] computeDefaultRuntimeClassPath( |
| IScriptProject jproject) throws CoreException { |
| IRuntimeBuildpathEntry[] unresolved = computeUnresolvedRuntimeBuildpath( |
| jproject); |
| // 1. remove bootpath entries |
| // 2. resolve & translate to local file system paths |
| List<String> resolved = new ArrayList<>(unresolved.length); |
| for (int i = 0; i < unresolved.length; i++) { |
| IRuntimeBuildpathEntry entry = unresolved[i]; |
| if (entry |
| .getBuildpathProperty() == IRuntimeBuildpathEntry.USER_ENTRY) { |
| IRuntimeBuildpathEntry[] entries = resolveRuntimeBuildpathEntry( |
| entry, jproject); |
| for (int j = 0; j < entries.length; j++) { |
| String location = entries[j].getLocation(); |
| if (location != null) { |
| resolved.add(location); |
| } |
| } |
| } |
| } |
| return resolved.toArray(new String[resolved.size()]); |
| } |
| |
| public static ISourceContainer[] getSourceContainers( |
| IRuntimeBuildpathEntry[] resolved) { |
| return ScriptSourceLookupUtil.translate(resolved); |
| } |
| |
| public static IRuntimeBuildpathEntry[] computeUnresolvedSourceBuildpath( |
| ILaunchConfiguration configuration) throws CoreException { |
| return getScriptpathProvider(configuration) |
| .computeUnresolvedBuildpath(configuration); |
| } |
| |
| } |