blob: 3adee7c50e699fc144e3d12d7f8dd8c5ba399f8e [file] [log] [blame]
/*=============================================================================#
# 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 );
}
}