/*=============================================================================# # Copyright (c) 2010-2016 Stephan Wahlbrink (WalWare.de) and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the GNU Lesser General Public License # v2.1 or newer, which accompanies this distribution, and is available at # http://www.gnu.org/licenses/lgpl.html # # Contributors: # Stephan Wahlbrink - initial API and implementation #=============================================================================*/ package de.walware.rj.rsetups; import java.io.File; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.ILog; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.URIUtil; import org.osgi.framework.Bundle; public class RSetupUtil { public static final String EXTENSION_POINT_ID = "de.walware.rj.rSetups"; //$NON-NLS-1$ private static final String PLUGIN_ID = "de.walware.rj.server"; //$NON-NLS-1$ private static final ILog LOGGER = Platform.getLog(Platform.getBundle(PLUGIN_ID)); private static final String SETUP_ELEMENT_NAME = "setup"; //$NON-NLS-1$ private static final String BASE_ELEMENT_NAME = "base"; //$NON-NLS-1$ private static final String LIBRARY_ELEMENT_NAME = "library"; //$NON-NLS-1$ private static final String ID_ATTRIBUTE_NAME = "id"; //$NON-NLS-1$ private static final String SETUP_ID_ATTRIBUTE_NAME = "setupId"; //$NON-NLS-1$ private static final String NAME_ATTRIBUTE_NAME = "name"; //$NON-NLS-1$ private static final String INHERIT_BASE_ATTRIBUTE_NAME = "inheritBase"; //$NON-NLS-1$ private static final String LOCATION_ATTRIBUTE_NAME = "location"; //$NON-NLS-1$ private static final String GROUP_ATTRIBUTE_NAME = "group"; //$NON-NLS-1$ /** * Loads all available R setups for the current or the specified platform. * * A filter map specifying a platform contains the arguments like <code>$os$</code> and * <code>$arch$</code> as keys; its values must be set to the known constant of the desired. * platform. * * @param filter a platform filter or <code>null</code> for the current platform * @return a list with available R setups */ public static List<RSetup> loadAvailableSetups(final Map<String, String> filter) { final Set<String> ids = new HashSet<>(); final List<RSetup> setups = new ArrayList<>(); final IConfigurationElement[] configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID); for (int i = 0; i < configurationElements.length; i++) { if (configurationElements[i].getName().equals(SETUP_ELEMENT_NAME)) { final String id = configurationElements[i].getAttribute(ID_ATTRIBUTE_NAME); if (id != null && id.length() > 0 && !ids.contains(id)) { ids.add(id); final RSetup setup = loadSetup(id, filter, configurationElements); if (setup != null) { setups.add(setup); } } } } return setups; } /** * Loads the R setup with the specified id for the current or the specified platform. * * A filter map specifying a platform contains the arguments like <code>$os$</code> and * <code>$arch$</code> as keys; its values must be set to the known constant of the desired. * platform. * * @param id the id of the R setup * @param filter a platform filter or <code>null</code> for the current platform * @return the R setup or <code>null</code> if loading failed */ public static RSetup loadSetup(final String id, final Map<String, String> filter) { final IConfigurationElement[] configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID); return loadSetup(id, filter, configurationElements); } private static RSetup loadSetup(final String id, final Map<String, String> filter, final IConfigurationElement[] configurationElements) { try { for (int i = 0; i < configurationElements.length; i++) { final IConfigurationElement element = configurationElements[i]; if (element.getName().equals(SETUP_ELEMENT_NAME) && id.equals(element.getAttribute(ID_ATTRIBUTE_NAME)) ) { final RSetup setup = new RSetup(id); if (filter != null && filter.containsKey("$os$")) { //$NON-NLS-1$ setup.setOS(filter.get("$os$"), filter.get("$arch$")); //$NON-NLS-1$ //$NON-NLS-2$ } else { setup.setOS(Platform.getOS(), Platform.getOSArch()); } setup.setName(element.getAttribute(NAME_ATTRIBUTE_NAME)); loadSetupBase(id, filter, configurationElements, setup); if (setup.getRHome() == null) { log(IStatus.WARNING, "Incomplete R setup: Missing R home for setup '" + id + "', the setup is ignored.", element); return null; } loadSetupLibraries(id, filter, configurationElements, setup); return setup; } } } catch (final Exception e) { LOGGER.log(new Status(IStatus.ERROR, PLUGIN_ID, "Error in R setup: Failed to load setup.", e)); } return null; } private static void loadSetupBase(final String id, final Map<String, String> filter, final IConfigurationElement[] configurationElements, final RSetup setup) throws Exception { for (int i = 0; i < configurationElements.length; i++) { final IConfigurationElement element = configurationElements[i]; if (element.getName().equals(BASE_ELEMENT_NAME) && id.equals(element.getAttribute(SETUP_ID_ATTRIBUTE_NAME)) ) { final String path = getLocation(element, filter); setup.setRHome(path); return; } } for (int i = 0; i < configurationElements.length; i++) { final IConfigurationElement element = configurationElements[i]; if (element.equals(SETUP_ELEMENT_NAME) && id.equals(element.getAttribute(SETUP_ID_ATTRIBUTE_NAME)) ) { final String inheritId = element.getAttribute(INHERIT_BASE_ATTRIBUTE_NAME); if (inheritId != null) { loadSetupBase(inheritId, filter, configurationElements, setup); } return; } } } private static void loadSetupLibraries(final String id, final Map<String, String> filter, final IConfigurationElement[] configurationElements, final RSetup setup) throws Exception { for (int i = 0; i < configurationElements.length; i++) { final IConfigurationElement element = configurationElements[i]; if (element.getName().equals(LIBRARY_ELEMENT_NAME) && id.equals(element.getAttribute(SETUP_ID_ATTRIBUTE_NAME)) ) { final String path = getLocation(element, filter); if (path == null) { continue; } final String groupId = element.getAttribute(GROUP_ATTRIBUTE_NAME); if (groupId == null || groupId.length() == 0 || groupId.equals("R_LIBS")) { //$NON-NLS-1$ setup.getRLibs().add(path); } else if (groupId.equals("R_LIBS_SITE")) { //$NON-NLS-1$ setup.getRLibsSite().add(path); } else if (groupId.equals("R_LIBS_USER")) { //$NON-NLS-1$ setup.getRLibsUser().add(path); } else { log(IStatus.WARNING, "Invalid R setup element: " + "Unknown library group '" + groupId + "', the library is ignored", element); } } } } private static String getLocation(final IConfigurationElement element, final Map<String, String> filter) throws Exception { final Bundle bundle = Platform.getBundle(element.getContributor().getName()); final String path = element.getAttribute(LOCATION_ATTRIBUTE_NAME); if (bundle != null && path != null && path.length() > 0) { final URL[] bundleURLs = FileLocator.findEntries(bundle, new Path(path), filter); for (int i = 0; i < bundleURLs.length; i++) { final URI fileURI = URIUtil.toURI(FileLocator.toFileURL(bundleURLs[i])); if (fileURI.getScheme().equals("file")) { //$NON-NLS-1$ final File file = new File(fileURI); if (file.exists() && file.isDirectory() && file.list().length > 0) { return file.getAbsolutePath(); } } } } return null; } private static void log(final int severity, final String message, final IConfigurationElement element) { final StringBuilder info = new StringBuilder(message); if (element != null) { info.append(" (contributed by '"); info.append(element.getContributor().getName()); info.append("')."); } LOGGER.log(new Status(IStatus.WARNING, PLUGIN_ID, info.toString())); } }