| /*=============================================================================# |
| # Copyright (c) 2007, 2019 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.internal.r.core.renv; |
| |
| import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullElse; |
| import static org.eclipse.statet.jcommons.lang.SystemUtils.OS_WIN; |
| |
| import java.beans.PropertyChangeListener; |
| import java.beans.PropertyChangeSupport; |
| import java.io.File; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.core.filesystem.EFS; |
| import org.eclipse.core.filesystem.IFileInfo; |
| import org.eclipse.core.filesystem.IFileStore; |
| import org.eclipse.core.filesystem.URIUtil; |
| import org.eclipse.core.net.proxy.IProxyData; |
| import org.eclipse.core.net.proxy.IProxyService; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.osgi.service.datalocation.Location; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.collections.ImList; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| import org.eclipse.statet.jcommons.lang.SystemUtils; |
| import org.eclipse.statet.jcommons.status.StatusException; |
| |
| import org.eclipse.statet.ecommons.io.FileUtil; |
| import org.eclipse.statet.ecommons.preferences.core.Preference; |
| import org.eclipse.statet.ecommons.preferences.core.Preference.IntPref; |
| import org.eclipse.statet.ecommons.preferences.core.Preference.NullableStringPref; |
| import org.eclipse.statet.ecommons.preferences.core.Preference.StringArrayPref; |
| import org.eclipse.statet.ecommons.preferences.core.Preference.StringPref; |
| import org.eclipse.statet.ecommons.preferences.core.PreferenceAccess; |
| import org.eclipse.statet.ecommons.preferences.core.util.PreferenceUtils; |
| import org.eclipse.statet.ecommons.runtime.core.util.StatusUtils; |
| |
| import org.eclipse.statet.internal.r.core.Messages; |
| import org.eclipse.statet.internal.r.core.RCorePlugin; |
| import org.eclipse.statet.r.core.RCore; |
| import org.eclipse.statet.r.core.RCorePreferenceNodes; |
| import org.eclipse.statet.r.core.renv.IREnvConfiguration; |
| import org.eclipse.statet.r.core.renv.IREnvManager; |
| import org.eclipse.statet.rhelp.core.REnvHelpConfiguration; |
| import org.eclipse.statet.rj.renv.core.BasicREnvConfiguration; |
| import org.eclipse.statet.rj.renv.core.BasicRLibLocation; |
| import org.eclipse.statet.rj.renv.core.DefaultLocalConfigurator; |
| import org.eclipse.statet.rj.renv.core.REnv; |
| import org.eclipse.statet.rj.renv.core.REnvConfiguration; |
| import org.eclipse.statet.rj.renv.core.RLibGroup; |
| import org.eclipse.statet.rj.renv.core.RLibLocation; |
| import org.eclipse.statet.rj.rsetups.RSetup; |
| |
| |
| public class REnvConfigurationImpl extends BasicREnvConfiguration |
| implements IREnvConfiguration, REnvHelpConfiguration { |
| |
| |
| private static final String PREFKEY_TYPE= "type"; //$NON-NLS-1$ |
| |
| private static final String PREFKEY_NAME= "name"; //$NON-NLS-1$ |
| |
| private static final String PREFKEY_RHOME_DIR= "env.r_home"; //$NON-NLS-1$ |
| |
| private static final String PREFKEY_SUBARCH= "env.sub_arch"; //$NON-NLS-1$ |
| |
| private static final String PREFKEY_RBITS= "env.r_bits.count"; //$NON-NLS-1$ |
| |
| private static final String PREFKEY_ROS= "env.r_os.type"; //$NON-NLS-1$ |
| |
| private static final String PREFKEY_RLIBS_PREFIX= "env.r_libs."; //$NON-NLS-1$ |
| |
| private static final String PREFKEY_RDOC_DIR= "env.r_doc.dir"; //$NON-NLS-1$ |
| private static final String PREFKEY_RSHARE_DIR= "env.r_share.dir"; //$NON-NLS-1$ |
| private static final String PREFKEY_RINCLUDE_DIR= "env.r_include.dir"; //$NON-NLS-1$ |
| |
| private static final String PREFKEY_INDEX_DIR= "index.dir"; //$NON-NLS-1$ |
| |
| |
| public static IPath getStateLocation(final REnv rEnv) { |
| return RCorePlugin.getInstance().getStateLocation().append("renv").append(rEnv.getId()); //$NON-NLS-1$ |
| } |
| |
| private static Path getStateRootDirectoryPath(final REnv rEnv) { |
| return Paths.get(URIUtil.toURI(getStateLocation(rEnv))); |
| } |
| |
| |
| private static RLibLocation createDefaultLocation() { |
| return new BasicRLibLocation(RLibLocation.R, DEFAULT_R_DEFAULT_LOCATION_DIRECTORY, null); |
| } |
| |
| private static final ImList<RLibGroup> DEFAULT_LIBS_INIT; |
| private static final ImList<RLibGroup> DEFAULT_LIBS_DEFAULTS; |
| static { |
| { final RLibGroup[] groups= new RLibGroup[DEFAULT_LIB_GROUP_IDS.size()]; |
| for (int i= 0; i < groups.length; i++) { |
| final String id= DEFAULT_LIB_GROUP_IDS.get(i); |
| final ImList<RLibLocation> libs= ImCollections.emptyList(); |
| groups[i]= new REnvManagerLibGroup.Final(id, REnvManagerLibGroup.getLabel(id), libs); |
| } |
| DEFAULT_LIBS_INIT= ImCollections.newList(groups); |
| } |
| { final RLibGroup[] groups= new RLibGroup[DEFAULT_LIB_GROUP_IDS.size()]; |
| for (int i= 0; i < groups.length; i++) { |
| final String id= DEFAULT_LIB_GROUP_IDS.get(i); |
| final ImList<RLibLocation> libs; |
| if (id == RLibGroup.R_DEFAULT) { |
| libs= ImCollections.newList(createDefaultLocation()); |
| } |
| else if (id == RLibGroup.R_SITE) { |
| libs= ImCollections.<RLibLocation>newList(new BasicRLibLocation( |
| RLibLocation.USER, DEFAULT_R_SITE_LOCATION_DIRECTORY, null )); |
| } |
| else { |
| libs= ImCollections.emptyList(); |
| } |
| groups[i]= new REnvManagerLibGroup.Final(id, REnvManagerLibGroup.getLabel(id), libs); |
| } |
| DEFAULT_LIBS_DEFAULTS= ImCollections.newList(groups); |
| } |
| } |
| |
| |
| public static class Editable extends REnvConfigurationImpl implements WorkingCopy { |
| |
| public Editable(final String type, final ActualREnv link) { |
| super(type, link, (PreferenceAccess) null, null); |
| loadDefaults(); |
| } |
| |
| private Editable(final REnvConfigurationImpl config) { |
| super(config.type, (ActualREnv) config.getREnv(), (PreferenceAccess) null, null); |
| load(config); |
| } |
| |
| |
| @Override |
| public void setName(final String name) { |
| final String oldValue= getName(); |
| super.setName(name); |
| firePropertyChange(PROP_NAME, oldValue, name); |
| } |
| |
| |
| @Override |
| public void setRHomeDirectory(final @Nullable String directory) { |
| final String oldValue= getRHomeDirectory(); |
| super.setRHomeDirectory(directory); |
| firePropertyChange(PROP_RHOME, oldValue, getRHomeDirectory()); |
| } |
| |
| @Override |
| public void setRArch(final String arch) { |
| final String oldValue= getRArch(); |
| super.setRArch(arch); |
| firePropertyChange(PROP_SUBARCH, oldValue, getRArch()); |
| } |
| |
| @Override |
| public void setROS(final String type) { |
| final String oldValue= getROS(); |
| super.setROS(type); |
| firePropertyChange(PROP_ROS, oldValue, getROS()); |
| } |
| |
| |
| @Override |
| public void setRShareDirectory(final @Nullable String directory) { |
| final String oldValue= getRShareDirectory(); |
| super.setRShareDirectory(directory); |
| firePropertyChange(PROP_RSHARE_DIRECTORY, oldValue, getRShareDirectory()); |
| } |
| |
| @Override |
| public void setRIncludeDirectory(final @Nullable String directory) { |
| final String oldValue= getRIncludeDirectory(); |
| super.setRIncludeDirectory(directory); |
| firePropertyChange(PROP_RINCLUDE_DIRECTORY, oldValue, getRIncludeDirectory()); |
| } |
| |
| @Override |
| public void setRDocDirectory(final @Nullable String directory) { |
| final String oldValue= getRDocDirectory(); |
| super.setRDocDirectory(directory); |
| firePropertyChange(PROP_RDOC_DIRECTORY, oldValue, getRDocDirectory()); |
| } |
| |
| @Override |
| protected ImList<REnvManagerLibGroup.Editable> copyLibs(final List<? extends RLibGroup> source) { |
| final REnvManagerLibGroup.Editable[] groups= new REnvManagerLibGroup.Editable[source.size()]; |
| for (int i= 0; i < groups.length; i++) { |
| groups[i]= new REnvManagerLibGroup.Editable(source.get(i)); |
| } |
| return ImCollections.newList(groups); |
| } |
| |
| @Override |
| public ImList<REnvManagerLibGroup.Editable> getRLibGroups() { |
| return (ImList<REnvManagerLibGroup.Editable>) super.getRLibGroups(); |
| } |
| |
| @Override |
| public REnvManagerLibGroup.Editable getRLibGroup(final String id) { |
| return (REnvManagerLibGroup.Editable) super.getRLibGroup(id); |
| } |
| |
| @Override |
| public void setStateSharedType(final String type) { |
| final String oldValue= getStateSharedType(); |
| super.setStateSharedType(type); |
| firePropertyChange(PROP_STATE_SHARED_TYPE, oldValue, getStateSharedType()); |
| } |
| |
| @Override |
| public void setStateSharedDirectory(final @Nullable String directory) { |
| final String oldValue= getStateSharedDirectory(); |
| super.setStateSharedDirectory(directory); |
| firePropertyChange(PROP_STATE_SHARED_DIRECTORY, oldValue, getStateSharedDirectory()); |
| } |
| |
| @Override |
| public void setStateSharedServer(final @Nullable String url) { |
| final String oldValue= getStateSharedServer(); |
| super.setStateSharedServer(url); |
| firePropertyChange(PROP_STATE_SHARED_SERVER, oldValue, getStateSharedServer()); |
| } |
| |
| } |
| |
| |
| private String type; |
| |
| private String nodeQualifier; |
| private String checkId; |
| |
| private StringPref prefType; |
| private StringPref prefName; |
| |
| private StringPref prefRHomeDirectory; |
| private StringPref prefRArch; |
| private IntPref prefRBits; |
| private int rBits; |
| private StringPref prefROS; |
| private String rOS; |
| |
| private String rVersion; |
| |
| private NullableStringPref prefRDocDirectory; |
| private NullableStringPref prefRShareDirectory; |
| private NullableStringPref prefRIncludeDirectory; |
| |
| private NullableStringPref prefStateSharedType; |
| private NullableStringPref prefStateSharedDirectory; |
| private NullableStringPref prefStateSharedServer; |
| |
| private Properties sharedProperties; |
| private final Object sharedPropertiesLock= new Object(); |
| |
| private final PropertyChangeSupport beanSupport= new PropertyChangeSupport(this); |
| |
| |
| protected REnvConfigurationImpl(final String type, final ActualREnv rEnv, |
| final PreferenceAccess prefs, final String key) { |
| super(rEnv, getStateRootDirectoryPath(rEnv)); |
| setType(type); |
| |
| this.nodeQualifier= IREnvManager.PREF_QUALIFIER + '/' + |
| ((key != null) ? key : rEnv.getId()); |
| |
| this.rBits= 64; |
| if (prefs != null) { |
| setRLibGroups(copyLibs(DEFAULT_LIBS_DEFAULTS)); |
| load(prefs); |
| } |
| else { |
| setRLibGroups(DEFAULT_LIBS_INIT); |
| } |
| } |
| |
| REnvConfigurationImpl(final String type, final ActualREnv rEnv, |
| final RSetup setup, final PreferenceAccess prefs) { |
| super(rEnv, getStateRootDirectoryPath(rEnv)); |
| assert (setup != null); |
| if (type != EPLUGIN_LOCAL_TYPE) { |
| throw new IllegalArgumentException(type); |
| } |
| setType(type); |
| |
| this.nodeQualifier= IREnvManager.PREF_QUALIFIER + '/' + rEnv.getId(); |
| |
| setName(setup.getName()); |
| setROS(setup.getOS()); |
| if (SystemUtils.getLocalOs() == OS_WIN) { |
| String arch= setup.getOSArch(); |
| if (arch == null || arch.isEmpty()) { |
| arch= Platform.getOSArch(); |
| } |
| setRArch(arch); |
| } |
| this.rBits= (Platform.ARCH_X86.equals(setup.getOSArch())) ? 32 : 64; |
| setRHomeDirectory(setup.getRHome()); |
| loadDefaultInstallDir(); |
| this.rVersion= setup.getRVersion(); |
| |
| final ImList<String> libGroupIds= DEFAULT_LIB_GROUP_IDS; |
| final List<RLibGroup> groups= new ArrayList<>(libGroupIds.size()); |
| final List<RLibLocation> libLocations= new ArrayList<>(); |
| |
| final String userHome= getUserHome(); |
| final String eclipseHome= getInstallLocation(); |
| |
| for (final String id : libGroupIds) { |
| libLocations.clear(); |
| final String label= REnvManagerLibGroup.getLabel(id); |
| if (label != null) { |
| final List<String> locations; |
| if (id == RLibGroup.R_DEFAULT) { |
| libLocations.add(createDefaultLocation()); |
| locations= null; |
| } |
| else if (id == RLibGroup.R_SITE) { |
| locations= setup.getRLibsSite(); |
| } |
| else if (id == RLibGroup.R_USER) { |
| locations= setup.getRLibsUser(); |
| try { |
| final String path= "${workspace_loc}/.metadata/.r/" + getREnv().getId() + "/user-library"; //$NON-NLS-1$ //$NON-NLS-2$ |
| final IFileStore store= FileUtil.expandToLocalFileStore(path, null, null); |
| if (!store.fetchInfo().exists()) { |
| store.mkdir(EFS.NONE, null); |
| } |
| libLocations.add(new BasicRLibLocation(RLibLocation.R, path, "Workspace Library")); |
| } |
| catch (final Exception e) { |
| RCorePlugin.log(new Status(IStatus.ERROR, RCore.BUNDLE_ID, |
| "An error occured when creating default R_USER 'Workspace Library'.", e)); |
| } |
| } |
| else if (id == RLibGroup.R_OTHER) { |
| locations= setup.getRLibs(); |
| } |
| else { |
| continue; |
| } |
| if (locations != null) { |
| for (int j= 0; j < locations.size(); j++) { |
| String path= locations.get(j); |
| if (eclipseHome != null && path.startsWith(eclipseHome)) { |
| path= "${eclipse_home}" + File.separatorChar + //$NON-NLS-1$ |
| path.substring(eclipseHome.length()); |
| } |
| else if (userHome != null && path.startsWith(userHome)) { |
| path= "${user_home}" + File.separatorChar + //$NON-NLS-1$ |
| path.substring(userHome.length()); |
| } |
| libLocations.add(new BasicRLibLocation(RLibLocation.EPLUGIN, path, null)); |
| } |
| } |
| groups.add(new REnvManagerLibGroup.Final(id, label, |
| ImCollections.toList(libLocations)) ); |
| } |
| else { |
| // unknown group |
| } |
| } |
| setRLibGroups(ImCollections.toList(groups)); |
| |
| if (prefs != null) { |
| load(prefs); |
| } |
| |
| resolvePaths(); |
| } |
| |
| private void setType(final @Nullable String type) { |
| final int flags; |
| if (type == USER_LOCAL_TYPE) { |
| flags= (LOCAL | SPEC_SETUP); |
| } |
| else if (type == USER_REMOTE_TYPE) { |
| flags= (REMOTE); |
| } |
| else if (type == EPLUGIN_LOCAL_TYPE) { |
| flags= (LOCAL | SPEC_SETUP); |
| } |
| else if (type != null && type.startsWith(CONTRIB_TEMP_REMOTE_TYPE)) { |
| flags= (REMOTE); |
| } |
| else { |
| flags= 0; |
| } |
| this.type= type; |
| setFlags(flags); |
| } |
| |
| private String getUserHome() { |
| IPath path= new org.eclipse.core.runtime.Path(System.getProperty("user.home")); //$NON-NLS-1$ |
| path= path.addTrailingSeparator(); |
| return path.toOSString(); |
| } |
| |
| private String getInstallLocation() { |
| final Location installLocation= Platform.getInstallLocation(); |
| if (installLocation == null) { |
| return null; |
| } |
| final URL url= installLocation.getURL(); |
| if (url == null) { |
| return null; |
| } |
| IPath path; |
| try { |
| path= URIUtil.toPath(url.toURI()); |
| } |
| catch (final URISyntaxException e) { |
| return null; |
| } |
| if (path == null) { |
| return null; |
| } |
| path= path.addTrailingSeparator(); |
| return path.toOSString(); |
| } |
| |
| public REnvConfigurationImpl(final IREnvConfiguration config) { |
| this(config.getType(), (ActualREnv) config.getREnv(), null, (String) null); |
| load(config); |
| } |
| |
| protected void checkPrefs(final PreferenceAccess prefs) { |
| final String id= getREnv().getId(); |
| if (id.equals(this.checkId)) { |
| return; |
| } |
| this.checkId= id; |
| |
| this.prefType= new StringPref(this.nodeQualifier, PREFKEY_TYPE); |
| |
| if (this.type == null && prefs != null) { |
| final String type= prefs.getPreferenceValue(this.prefType); |
| if (type != null) { |
| setType(type.intern()); |
| } |
| } |
| |
| this.prefName= new StringPref(this.nodeQualifier, PREFKEY_NAME); |
| this.prefROS= new StringPref(this.nodeQualifier, PREFKEY_ROS); |
| if (this.type == USER_LOCAL_TYPE) { |
| this.prefRHomeDirectory= new StringPref(this.nodeQualifier, PREFKEY_RHOME_DIR); |
| this.prefRArch= new StringPref(this.nodeQualifier, PREFKEY_SUBARCH); |
| this.prefRBits= new IntPref(this.nodeQualifier, PREFKEY_RBITS); |
| this.prefRDocDirectory= new NullableStringPref(this.nodeQualifier, PREFKEY_RDOC_DIR); |
| this.prefRShareDirectory= new NullableStringPref(this.nodeQualifier, PREFKEY_RSHARE_DIR); |
| this.prefRIncludeDirectory= new NullableStringPref(this.nodeQualifier, PREFKEY_RINCLUDE_DIR); |
| } |
| this.prefStateSharedType= new NullableStringPref(this.nodeQualifier, STATE_SHARED_TYPE_KEY); |
| this.prefStateSharedDirectory= new NullableStringPref(this.nodeQualifier, STATE_SHARED_DIRECTORY_PATH_KEY); |
| this.prefStateSharedServer= new NullableStringPref(this.nodeQualifier, STATE_SHARED_SERVER_URI_KEY); |
| } |
| |
| void upgradePref() { |
| this.checkId= null; |
| this.nodeQualifier= IREnvManager.PREF_QUALIFIER + '/' + getREnv().getId(); |
| } |
| |
| protected void checkExistence(final PreferenceAccess prefs) { |
| // final IEclipsePreferences[] nodes= prefs.getPreferenceNodes(RCorePreferenceNodes.CAT_R_ENVIRONMENTS_QUALIFIER); |
| // if (nodes.length > 0) { |
| // try { |
| // if (!nodes[0].nodeExists(this.checkId)) { |
| // throw new IllegalArgumentException("A REnv configuration with this name does not exists."); |
| // } |
| // } |
| // catch (final BackingStoreException e) { |
| // throw new IllegalArgumentException("REnv Configuration could not be accessed."); |
| // } |
| // } |
| } |
| |
| |
| @Override |
| public String getType() { |
| return this.type; |
| } |
| |
| @Override |
| public boolean isEditable() { |
| return (this.type == USER_LOCAL_TYPE || this.type == USER_REMOTE_TYPE); |
| } |
| |
| |
| @Override |
| public String getPrefNodeQualifier() { |
| checkPrefs(null); |
| return this.nodeQualifier; |
| } |
| |
| public void loadDefaults() { |
| if (!(this instanceof WorkingCopy)) { |
| throw new UnsupportedOperationException("No working copy"); |
| } |
| setName("R"); //$NON-NLS-1$ |
| if (this.type == USER_LOCAL_TYPE) { |
| setRHomeDirectory(""); //$NON-NLS-1$ |
| setRLibGroups(copyLibs(DEFAULT_LIBS_DEFAULTS)); |
| } |
| if (isLocal()) { |
| loadDefaultInstallDir(); |
| } |
| |
| resolvePaths(); |
| } |
| |
| private void loadDefaultInstallDir() { |
| setRDocDirectory(DEFAULT_R_DOC_DIRECTORY); |
| setRShareDirectory(DEFAULT_R_SHARE_DIRECTORY); |
| setRIncludeDirectory(DEFAULT_R_INCLUDE_DIRECTORY); |
| } |
| |
| public void load(final IREnvConfiguration from) { |
| setName(from.getName()); |
| setROS(from.getROS()); |
| if (isLocal()) { |
| setRHomeDirectory(from.getRHomeDirectory()); |
| setRArch(from.getRArch()); |
| this.rBits= (from instanceof REnvConfigurationImpl) ? ((REnvConfigurationImpl) from).rBits : 64; |
| setRDocDirectory(from.getRDocDirectory()); |
| setRShareDirectory(from.getRShareDirectory()); |
| setRIncludeDirectory(from.getRIncludeDirectory()); |
| setRLibGroups(copyLibs(from.getRLibGroups())); |
| } |
| { setStateSharedType(from.getStateSharedType()); |
| String directory= null; |
| String server= null; |
| switch (getStateSharedType()) { |
| case SHARED_DIRECTORY: |
| directory= from.getStateSharedDirectory(); |
| break; |
| case SHARED_SERVER: |
| server= from.getStateSharedServer(); |
| break; |
| } |
| setStateSharedDirectory(directory); |
| setStateSharedServer(server); |
| } |
| resolvePaths(); |
| } |
| |
| public void load(final PreferenceAccess prefs) { |
| checkPrefs(prefs); |
| checkExistence(prefs); |
| |
| if (isEditable()) { |
| setName(prefs.getPreferenceValue(this.prefName)); |
| setROS(prefs.getPreferenceValue(this.prefROS)); |
| } |
| if (this.type == USER_LOCAL_TYPE) { |
| setRHomeDirectory(prefs.getPreferenceValue(this.prefRHomeDirectory)); |
| setRArch(prefs.getPreferenceValue(this.prefRArch)); |
| this.rBits= prefs.getPreferenceValue(this.prefRBits); |
| setRDocDirectory(prefs.getPreferenceValue(this.prefRDocDirectory)); |
| setRShareDirectory(prefs.getPreferenceValue(this.prefRShareDirectory)); |
| setRIncludeDirectory(prefs.getPreferenceValue(this.prefRIncludeDirectory)); |
| } |
| if (isLocal()) { |
| final ImList<String> libGroupIds= DEFAULT_LIB_GROUP_IDS; |
| final List<RLibGroup> groups= new ArrayList<>(libGroupIds.size()); |
| for (final String id : libGroupIds) { |
| final List<RLibLocation> libs= new ArrayList<>(); |
| final RLibGroup group= getRLibGroup(id); |
| for (final RLibLocation location : group.getLibLocations()) { |
| if (location.getSource() != RLibLocation.USER) { |
| libs.add(location); |
| } |
| } |
| if (id != RLibGroup.R_DEFAULT) { |
| final String[] paths= prefs.getPreferenceValue( |
| new StringArrayPref(this.nodeQualifier, PREFKEY_RLIBS_PREFIX + id, Preference.IS2_SEPARATOR_CHAR) ); |
| for (final String path : paths) { |
| final RLibLocation location= new BasicRLibLocation(RLibLocation.USER, path, null); |
| if (!libs.contains(location)) { |
| libs.add(location); |
| } |
| } |
| } |
| groups.add(new REnvManagerLibGroup.Final(id, REnvManagerLibGroup.getLabel(id), |
| ImCollections.toList(libs) )); |
| } |
| setRLibGroups(ImCollections.toList(groups)); |
| } |
| |
| setStateSharedType(nonNullElse(prefs.getPreferenceValue(this.prefStateSharedType), SHARED_DIRECTORY)); |
| setStateSharedDirectory(prefs.getPreferenceValue(this.prefStateSharedDirectory)); |
| setStateSharedServer(prefs.getPreferenceValue(this.prefStateSharedServer)); |
| |
| resolvePaths(); |
| } |
| |
| protected ImList<? extends RLibGroup> copyLibs(final List<? extends RLibGroup> source) { |
| final RLibGroup[] groups= new RLibGroup[source.size()]; |
| for (int i= 0; i < groups.length; i++) { |
| groups[i]= new REnvManagerLibGroup.Final(source.get(i)); |
| } |
| return ImCollections.newList(groups); |
| } |
| |
| public Map<Preference<?>, Object> deliverToPreferencesMap(final Map<Preference<?>, Object> map) { |
| checkPrefs(null); |
| |
| map.put(this.prefType, getType()); |
| |
| if (isEditable()) { |
| map.put(this.prefName, getName()); |
| map.put(this.prefROS, getROS()); |
| } |
| |
| if (this.type == USER_LOCAL_TYPE) { |
| map.put(this.prefRHomeDirectory, getRHomeDirectory()); |
| map.put(this.prefRArch, getRArch()); |
| map.put(this.prefRBits, this.rBits); |
| map.put(this.prefRDocDirectory, getRDocDirectory()); |
| map.put(this.prefRShareDirectory, getRShareDirectory()); |
| map.put(this.prefRIncludeDirectory, getRIncludeDirectory()); |
| } |
| if (isLocal()) { |
| final List<? extends RLibGroup> groups= getRLibGroups(); |
| for (final RLibGroup group : groups) { |
| final List<? extends RLibLocation> libraries= group.getLibLocations(); |
| final List<String> locations= new ArrayList<>(libraries.size()); |
| for (final RLibLocation location : libraries) { |
| if (location.getSource() == RLibLocation.USER) { |
| locations.add(location.getDirectory()); |
| } |
| } |
| map.put(new StringArrayPref(this.nodeQualifier, PREFKEY_RLIBS_PREFIX + group.getId(), |
| Preference.IS2_SEPARATOR_CHAR ), locations.toArray(new String[locations.size()])); |
| } |
| } |
| |
| map.put(this.prefStateSharedType, getStateSharedType()); |
| map.put(this.prefStateSharedDirectory, getStateSharedDirectory()); |
| map.put(this.prefStateSharedServer, getStateSharedServer()); |
| |
| return map; |
| } |
| |
| @Override |
| public Editable createWorkingCopy() { |
| return new Editable(this); |
| } |
| |
| public REnvConfigurationImpl getBaseConfiguration() { |
| return this; |
| } |
| |
| |
| /*-- Properties --------------------------------------------------------------*/ |
| |
| public void addPropertyChangeListener(final PropertyChangeListener listener) { |
| this.beanSupport.addPropertyChangeListener(listener); |
| } |
| |
| public void addPropertyChangeListener(final String propertyName, |
| final PropertyChangeListener listener) { |
| this.beanSupport.addPropertyChangeListener(propertyName, listener); |
| } |
| |
| public void removePropertyChangeListener(final PropertyChangeListener listener) { |
| this.beanSupport.removePropertyChangeListener(listener); |
| } |
| |
| public void removePropertyChangeListener(final String propertyName, |
| final PropertyChangeListener listener) { |
| this.beanSupport.removePropertyChangeListener(propertyName, listener); |
| } |
| |
| protected void firePropertyChange(final String propertyName, final String oldValue, final String newValue) { |
| this.beanSupport.firePropertyChange(propertyName, oldValue, newValue); |
| } |
| |
| |
| @Override |
| public String getRVersion() { |
| return this.rVersion; |
| } |
| |
| public boolean isValidRHomeLocation(final IFileStore rHome) { |
| final IFileStore binDir= rHome.getChild("bin"); //$NON-NLS-1$ |
| IFileStore exeFile= null; |
| switch (SystemUtils.getLocalOs()) { |
| case OS_WIN: |
| exeFile= binDir.getChild("R.exe"); //$NON-NLS-1$ |
| break; |
| default: |
| exeFile= binDir.getChild("R"); //$NON-NLS-1$ |
| break; |
| } |
| final IFileInfo info= exeFile.fetchInfo(); |
| return (!info.isDirectory() && info.exists()); |
| } |
| |
| /** {@link IREnvConfiguration.WorkingCopy#searchAvailableSubArchs(IFileStore)} */ |
| public List<String> searchAvailableSubArchs(final IFileStore rHome) { |
| if (rHome != null && rHome.fetchInfo().exists()) { |
| try { |
| final IFileStore rHomeBinSub; |
| final String name; |
| switch (SystemUtils.getLocalOs()) { |
| case OS_WIN: |
| rHomeBinSub= rHome.getChild("bin"); //$NON-NLS-1$ |
| name= "R.exe"; //$NON-NLS-1$ |
| break; |
| default: |
| rHomeBinSub= rHome.getChild("bin").getChild("exec"); //$NON-NLS-1$ //$NON-NLS-2$ |
| name= "R"; //$NON-NLS-1$ |
| break; |
| } |
| if (rHomeBinSub.fetchInfo().exists()) { |
| final IFileStore[] subDirs= rHomeBinSub.childStores(EFS.NONE, null); |
| final List<String> archs= new ArrayList<>(); |
| for (final IFileStore subDir : subDirs) { |
| if (subDir.getChild(name).fetchInfo().exists()) { |
| final String arch= normalizeRArch(subDir.getName()); |
| if (arch != null) { |
| archs.add(arch); |
| } |
| } |
| } |
| return archs; |
| } |
| } |
| catch (final CoreException e) {} |
| } |
| return null; |
| } |
| |
| @Override |
| public IStatus validate() { |
| CoreException error= null; |
| if (isLocal()) { |
| IFileStore rloc= null; |
| try { |
| rloc= FileUtil.expandToLocalFileStore(getRHomeDirectory(), null, null); |
| } |
| catch (final CoreException e) { |
| error= e; |
| } |
| if (rloc == null || !isValidRHomeLocation(rloc)) { |
| return new Status(IStatus.ERROR, RCore.BUNDLE_ID, Messages.REnvConfiguration_Validation_error_InvalidRHome_message, error); |
| } |
| } |
| return Status.OK_STATUS; |
| } |
| |
| |
| @Override |
| protected void setRHomeDirectory(@Nullable String directory) { |
| directory= updatePathSpec(directory); |
| super.setRHomeDirectory(directory); |
| } |
| |
| @Override |
| public String getROS() { |
| return this.rOS; |
| } |
| |
| protected void setROS(final String type) { |
| this.rOS= type; |
| } |
| |
| |
| @Override |
| protected void setRShareDirectory(@Nullable String directory) { |
| directory= updateRDirectoryPathSpec(directory); |
| super.setRShareDirectory(directory); |
| } |
| |
| @Override |
| protected void setRIncludeDirectory(@Nullable String directory) { |
| directory= updateRDirectoryPathSpec(directory); |
| super.setRIncludeDirectory(directory); |
| } |
| |
| @Override |
| protected void setRDocDirectory(@Nullable String directory) { |
| directory= updateRDirectoryPathSpec(directory); |
| super.setRDocDirectory(directory); |
| } |
| |
| @Override |
| protected void setStateSharedDirectory(@Nullable String directory) { |
| directory= updatePathSpec(directory); |
| super.setStateSharedDirectory(directory); |
| } |
| |
| |
| @Override |
| public List<String> getExecCommand(String arg1, final Set<Exec> execTypes) throws CoreException { |
| final String test= (arg1 != null) ? arg1.trim().toUpperCase() : ""; //$NON-NLS-1$ |
| Exec type= Exec.COMMON; |
| if (test.equals("CMD")) { //$NON-NLS-1$ |
| if (execTypes.contains(Exec.CMD)) { |
| type= Exec.CMD; |
| arg1= null; |
| } |
| } |
| else { |
| if (execTypes.contains(Exec.TERM)) { |
| type= Exec.TERM; |
| } |
| } |
| final List<String> commandLine= getExecCommand(type); |
| if (arg1 != null) { |
| commandLine.add(arg1); |
| } |
| return commandLine; |
| } |
| |
| @Override |
| public List<String> getExecCommand(final Exec execType) throws CoreException { |
| final List<IFileStore> binDirs= getBinDirs(); |
| IFileStore exe= null; |
| final List<String> commandLine= new ArrayList<>(2); |
| switch (execType) { |
| case TERM: |
| if (SystemUtils.getLocalOs() == OS_WIN) { |
| exe= getExisting(binDirs, "Rterm.exe"); //$NON-NLS-1$ |
| } |
| break; |
| case CMD: |
| if (SystemUtils.getLocalOs() == OS_WIN) { |
| exe= getExisting(binDirs, "Rcmd.exe"); //$NON-NLS-1$ |
| } |
| if (exe == null) { |
| commandLine.add("CMD"); //$NON-NLS-1$ |
| } |
| break; |
| default: |
| break; |
| } |
| if (exe == null) { |
| if (SystemUtils.getLocalOs() == OS_WIN) { |
| exe= getExisting(binDirs, "R.exe"); //$NON-NLS-1$ |
| } |
| else { |
| exe= getExisting(binDirs, "R"); //$NON-NLS-1$ |
| } |
| } |
| |
| commandLine.add(0, URIUtil.toPath(exe.toURI()).toOSString()); |
| return commandLine; |
| } |
| |
| private List<IFileStore> getBinDirs() throws CoreException { |
| final IFileStore rHome= FileUtil.expandToLocalFileStore(getRHomeDirectory(), null, null); |
| final IFileStore rHomeBin= rHome.getChild("bin"); //$NON-NLS-1$ |
| final IFileStore rHomeBinSub; |
| if (SystemUtils.getLocalOs() == OS_WIN) { |
| rHomeBinSub= rHomeBin; |
| } |
| else { // use wrapper shell scripts |
| rHomeBinSub= null; // rHomeBin.getChild("exec"); |
| } |
| final List<IFileStore> dirs= new ArrayList<>(4); |
| String arch= getRArch(); |
| if (arch == null) { |
| arch= Platform.getOSArch(); |
| } |
| if (arch != null && rHomeBinSub != null) { |
| final IFileStore rHomeBinArch; |
| if (arch.equals(Platform.ARCH_X86_64)) { |
| rHomeBinArch= getExistingChild(rHomeBinSub, "x86_64", "x64"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| else if (arch.equals(Platform.ARCH_X86)) { |
| rHomeBinArch= getExistingChild(rHomeBinSub, "x86", "i386", "i586", "i686"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } |
| else { |
| rHomeBinArch= getExistingChild(rHomeBinSub, arch); |
| } |
| if (rHomeBinArch != null) { |
| dirs.add(rHomeBinArch); |
| } |
| } |
| dirs.add(rHomeBin); |
| return dirs; |
| } |
| |
| private IFileStore getExistingChild(final IFileStore base, final String... names) { |
| for (final String name : names) { |
| final IFileStore child= base.getChild(name); |
| if (child.fetchInfo().exists()) { |
| return child; |
| } |
| } |
| return null; |
| } |
| |
| private IFileStore getExisting(final List<IFileStore> dirs, final String name) { |
| IFileStore file= null; |
| for (final IFileStore dir : dirs) { |
| file= dir.getChild(name); |
| if (file.fetchInfo().exists()) { |
| break; |
| } |
| } |
| return file; |
| } |
| |
| |
| @Override |
| public Map<String, String> getEnvironmentsVariables() throws CoreException { |
| try { |
| final DefaultLocalConfigurator setup= new DefaultLocalConfigurator(this); |
| final Map<String, String> envp= setup.getEnvironmentsVariables(0); |
| |
| if (PreferenceUtils.getInstancePrefs().getPreferenceValue(RCorePreferenceNodes.PREF_RENV_NETWORK_USE_ECLIPSE)) { |
| configureNetwork(envp); |
| } |
| |
| return envp; |
| } |
| catch (final StatusException e) { |
| throw StatusUtils.convert(e); |
| } |
| } |
| |
| protected void configureNetwork(final Map<String, String> envp) { |
| final IProxyService proxyService= RCorePlugin.getInstance().getProxyService(); |
| if (proxyService != null && proxyService.isProxiesEnabled()) { |
| final StringBuilder sb= new StringBuilder(); |
| { final String[] nonProxiedHosts= proxyService.getNonProxiedHosts(); |
| if (nonProxiedHosts.length > 0) { |
| sb.setLength(0); |
| sb.append(nonProxiedHosts[0]); |
| for (int i= 1; i < nonProxiedHosts.length; i++) { |
| sb.append(','); |
| sb.append(nonProxiedHosts[i]); |
| } |
| envp.put("no_proxy", sb.toString()); //$NON-NLS-1$ |
| } |
| } |
| if (SystemUtils.getLocalOs() == OS_WIN && proxyService.isSystemProxiesEnabled()) { |
| envp.put("R_NETWORK", "2"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| else { |
| IProxyData data= proxyService.getProxyData(IProxyData.HTTP_PROXY_TYPE); |
| if (data != null && data.getHost() != null) { |
| sb.setLength(0); |
| sb.append("http://"); //$NON-NLS-1$ |
| if (data.isRequiresAuthentication()) { |
| if (data.getPassword() == null || data.getPassword().isEmpty()) { |
| envp.put("http_proxy_user", "ask"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| else { |
| sb.append((data.getUserId() != null) ? data.getUserId() : "") //$NON-NLS-1$ |
| .append(':').append(data.getPassword()); |
| sb.append('@'); |
| } |
| } |
| sb.append(data.getHost()); |
| if (data.getPort() > 0) { |
| sb.append(':').append(data.getPort()); |
| } |
| sb.append('/'); |
| envp.put("http_proxy", sb.toString()); //$NON-NLS-1$ |
| } |
| |
| data= proxyService.getProxyData("FTP"); //$NON-NLS-1$ |
| if (data != null && data.getHost() != null) { |
| sb.setLength(0); |
| sb.append("ftp://"); //$NON-NLS-1$ |
| sb.append(data.getHost()); |
| if (data.getPort() > 0) { |
| sb.append(':').append(data.getPort()); |
| } |
| sb.append('/'); |
| envp.put("ftp_proxy", sb.toString()); //$NON-NLS-1$ |
| |
| if (data.isRequiresAuthentication()) { |
| if (data.getUserId() != null) { |
| envp.put("ftp_proxy_user", data.getUserId()); //$NON-NLS-1$ |
| } |
| if (data.getPassword() != null) { |
| envp.put("ftp_proxy_password", data.getPassword()); //$NON-NLS-1$ |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| // public IFileStore resolvePath(final String path) { |
| // if (isRemote()) { |
| // final Properties auto= getSharedProperties(); |
| // if (auto != null) { |
| // final String hostname= auto.getProperty("renv.hostname"); //$NON-NLS-1$ |
| // if (hostname != null) { |
| // final IResourceMappingManager rmManager= ResourceMappingUtils.getManager(); |
| // if (rmManager != null) { |
| // return rmManager.mapRemoteResourceToFileStore(hostname, |
| // new org.eclipse.core.runtime.Path(path), null ); |
| // } |
| // return null; |
| // } |
| // } |
| // } |
| // try { |
| // return FileUtil.getLocalFileStore(path); |
| // } |
| // catch (final CoreException e) { |
| // return null; |
| // } |
| // } |
| // |
| // public Properties getSharedProperties() { |
| // synchronized (this.sharedPropertiesLock) { |
| // if (this.sharedProperties == null) { |
| // loadSharedProperties(); |
| // } |
| // return this.sharedProperties; |
| // } |
| // } |
| // |
| // private void loadSharedProperties() { |
| // synchronized (this.sharedPropertiesLock) { |
| // InputStream in= null; |
| // try { |
| // final Path sharedStateDirectory= getStateSharedDirectoryPath(); |
| // if (sharedStateDirectory != null) { |
| // final Path propFile= sharedStateDirectory.resolve("renv.properties"); //$NON-NLS-1$ |
| // if (Files.isRegularFile(propFile)) { |
| // final Properties prop= new Properties(); |
| // final FileTime lastModified= Files.getLastModifiedTime(propFile); |
| // in= Files.newInputStream(propFile); |
| // prop.load(in); |
| // prop.setProperty("stamp", Long.toString(lastModified.toMillis())); //$NON-NLS-1$ |
| // this.sharedProperties= prop; |
| // in.close(); |
| // in= null; |
| // } |
| // } |
| // } |
| // catch (final Exception e) { |
| // RCorePlugin.log(new Status(IStatus.ERROR, RCore.BUNDLE_ID, 0, |
| // "An error occurrend when loading shared R environment properties.", e )); |
| // this.sharedProperties= new Properties(); |
| // } |
| // finally { |
| // if (in != null) { |
| // try { |
| // in.close(); |
| // } |
| // catch (final IOException e) {} |
| // } |
| // } |
| // } |
| // } |
| // |
| // public void updateSharedProperties(final Map<String, String> properties) { |
| // if (properties == null) { |
| // return; |
| // } |
| // synchronized (this.sharedPropertiesLock) { |
| // this.sharedProperties= null; |
| // final Properties prop= new Properties(); |
| // prop.putAll(properties); |
| // saveSharedProperties(prop); |
| // final IREnvConfiguration rEnvConfig= getREnv().get(IREnvConfiguration.class); |
| // if (rEnvConfig != null && rEnvConfig instanceof REnvConfigurationImpl) { |
| // ((REnvConfigurationImpl) rEnvConfig).loadSharedProperties(); |
| // } |
| // } |
| // } |
| // |
| // private void saveSharedProperties(final Properties prop) { |
| // OutputStream out= null; |
| // try { |
| // final Path sharedStateDirectory= getStateSharedDirectoryPath(); |
| // if (sharedStateDirectory != null) { |
| // final Path propFile= sharedStateDirectory.resolve("renv.properties"); //$NON-NLS-1$ |
| // out= Files.newOutputStream(propFile); |
| // prop.store(out, null); |
| // out.close(); |
| // out= null; |
| // } |
| // } |
| // catch (final Exception e) { |
| // RCorePlugin.log(new Status(IStatus.ERROR, RCore.BUNDLE_ID, 0, |
| // "An error occurrend when saving shared R environment properties.", e )); |
| // } |
| // finally { |
| // if (out != null) { |
| // try { |
| // out.close(); |
| // } |
| // catch (final IOException e) {} |
| // } |
| // } |
| // } |
| |
| |
| private static final Pattern RHOME_OLD_PATTERN= Pattern.compile("${env_var:R_HOME}", Pattern.LITERAL); |
| private static final String RHOME_NEW_STRING= Matcher.quoteReplacement("${r_home}"); |
| private static final String USERHOME_OLD_STRING= Matcher.quoteReplacement("~/"); |
| private static final String USERHOME_NEW_STRING= Matcher.quoteReplacement("${user_home}"); |
| |
| private static String updatePathSpec(@Nullable String spec) { |
| if (spec == null) { |
| return null; |
| } |
| if (spec.startsWith(USERHOME_OLD_STRING)) { |
| spec= USERHOME_NEW_STRING + spec.substring(1); |
| } |
| return spec; |
| } |
| |
| private static String updateRDirectoryPathSpec(@Nullable String spec) { |
| if (spec == null) { |
| return null; |
| } |
| spec= updatePathSpec(spec); |
| spec= RHOME_OLD_PATTERN.matcher(spec).replaceAll(RHOME_NEW_STRING); |
| return spec; |
| } |
| |
| @Override |
| protected @Nullable Path resolvePath(final String spec) throws Exception { |
| final IFileStore fileStore= FileUtil.expandToLocalFileStore(spec, null, null); |
| if (fileStore != null) { |
| return Paths.get(fileStore.toURI()); |
| } |
| return null; |
| } |
| |
| |
| @Override |
| protected boolean equalsType(final REnvConfiguration other) { |
| return (other instanceof REnvConfigurationImpl |
| && this.type == ((REnvConfigurationImpl) other).type ); |
| } |
| |
| } |