blob: a6ea672ceb31cde2aa50325c9f3ebe3e803383f3 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2010, 2018 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.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.osgi.framework.Bundle;
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;
public class RSetupUtil {
public static final String EXTENSION_POINT_ID= "org.eclipse.statet.rj.RSetups"; //$NON-NLS-1$
private static final String BUNDLE_ID= "org.eclipse.statet.rj.server"; //$NON-NLS-1$
private static final ILog LOGGER= Platform.getLog(Platform.getBundle(BUNDLE_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, BUNDLE_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, BUNDLE_ID, info.toString()));
}
}