| /*=============================================================================# |
| # Copyright (c) 2012, 2020 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.renv.core; |
| |
| import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert; |
| import static org.eclipse.statet.jcommons.lang.SystemUtils.OS_MAC; |
| import static org.eclipse.statet.jcommons.lang.SystemUtils.OS_WIN; |
| |
| import java.io.File; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| import org.eclipse.statet.jcommons.lang.SystemUtils; |
| import org.eclipse.statet.jcommons.status.Status; |
| import org.eclipse.statet.jcommons.status.StatusException; |
| import org.eclipse.statet.jcommons.status.WarningStatus; |
| |
| import org.eclipse.statet.internal.rj.renv.core.REnvCoreInternals; |
| |
| |
| @NonNullByDefault |
| public class DefaultLocalConfigurator { |
| |
| |
| /** Returns first directory which exists */ |
| private static final @Nullable Path getFirstDirectory( |
| final Path baseDirectory, final String... names) { |
| for (final String name : names) { |
| final Path directory= baseDirectory.resolve(name); |
| if (Files.isDirectory(directory)) { |
| return directory; |
| } |
| } |
| return null; |
| } |
| |
| /** Returns first directory which exists */ |
| private static final @Nullable Path getFirstDirectoryWith( |
| final List<Path> directories, final String name) { |
| for (final Path directory : directories) { |
| final Path file= directory.resolve(name); |
| if (Files.isRegularFile(file)) { |
| return directory; |
| } |
| } |
| return null; |
| } |
| |
| |
| public static final int MINIMAL_SETUP= 1; |
| |
| |
| private final REnvConfiguration config; |
| |
| |
| public DefaultLocalConfigurator(final REnvConfiguration config) { |
| this.config= config; |
| } |
| |
| |
| protected REnvConfiguration getConfig() { |
| return this.config; |
| } |
| |
| protected @Nullable String getSystemEnvVar(final String name) { |
| return System.getenv(name); |
| } |
| |
| public @Nullable String getRArch() { |
| final String arch= this.config.getRArch(); |
| if (arch == null) { |
| return null; |
| } |
| if (SystemUtils.getLocalOs() == OS_WIN) { |
| switch (arch) { |
| case SystemUtils.ARCH_X86_64: |
| return "x64"; //$NON-NLS-1$ |
| case SystemUtils.ARCH_X86_32: |
| return "i386"; //$NON-NLS-1$ |
| } |
| } |
| return arch; |
| } |
| |
| public Map<String, String> getEnvironmentsVariables(final int options) throws StatusException { |
| if (!this.config.isLocal() |
| || (this.config instanceof BasicREnvConfiguration |
| && (((BasicREnvConfiguration) this.config).getFlags() & BasicREnvConfiguration.SPEC_SETUP) == 0 )) { |
| throw new UnsupportedOperationException(); |
| } |
| if (this.config.getValidationStatus().getSeverity() == Status.ERROR) { |
| // ? |
| } |
| |
| final Map<String, String> envp= new HashMap<>(); |
| |
| envp.put("R_HOME", getRHomeDirectory().toString()); //$NON-NLS-1$ |
| switch (SystemUtils.getLocalOs()) { |
| case OS_WIN: |
| putPrepend(envp, "PATH", //$NON-NLS-1$ |
| checkLibDirectory(getRBinDirectoryCandidates(), "R.dll") ); //$NON-NLS-1$ |
| // libs in path |
| break; |
| case OS_MAC: |
| putPrepend(envp, "PATH", //$NON-NLS-1$ |
| getRHomeDirectory().resolve("bin") ); //$NON-NLS-1$ |
| if ((options & MINIMAL_SETUP) == 0) { |
| putPrepend(envp, "DYLD_LIBRARY_PATH", //$NON-NLS-1$ |
| getRHomeDirectory().resolve("lib") ); //$NON-NLS-1$ |
| } |
| break; |
| default: |
| putPrepend(envp, "PATH", //$NON-NLS-1$ |
| getRHomeDirectory().resolve("bin") ); //$NON-NLS-1$ |
| if ((options & MINIMAL_SETUP) == 0) { |
| putPrepend(envp, "LD_LIBRARY_PATH", //$NON-NLS-1$ |
| checkLibDirectory(getRLibDirectoryCandidates(), "libR.so") ); //$NON-NLS-1$ |
| } |
| break; |
| } |
| if ((options & MINIMAL_SETUP) == 0) { |
| final String rArch= getRArch(); |
| if (rArch != null && isArchAvailable(rArch)) { |
| envp.put("R_ARCH", '/' + rArch); |
| } |
| putIfNonNull(envp, "R_SHARE_DIR", this.config.getRShareDirectoryPath()); |
| putIfNonNull(envp, "R_INCLUDE_DIR", this.config.getRIncludeDirectoryPath()); |
| putIfNonNull(envp, "R_DOC_DIR", this.config.getRDocDirectoryPath()); |
| |
| putIfNonNull(envp, "R_LIBS_SITE", //$NON-NLS-1$ |
| getLibPathString(this.config.getRLibGroup(RLibGroup.R_SITE)) ); |
| putIfNonNull(envp, "R_LIBS_USER", //$NON-NLS-1$ |
| getLibPathString(this.config.getRLibGroup(RLibGroup.R_USER)) ); |
| putIfNonNull(envp, "R_LIBS", //$NON-NLS-1$ |
| getLibPathString(this.config.getRLibGroup(RLibGroup.R_OTHER)) ); |
| } |
| |
| envp.put("LC_NUMERIC", "C"); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| return envp; |
| } |
| |
| |
| protected final Path getRHomeDirectory() { |
| return nonNullAssert(this.config.getRHomeDirectoryPath()); |
| } |
| |
| protected boolean isArchAvailable(final String rArch) { |
| try { |
| final Path rHomeBin= getRHomeDirectory().resolve("bin"); //$NON-NLS-1$ |
| final Path rHomeBinSub; |
| final String name; |
| switch (SystemUtils.getLocalOs()) { |
| case OS_WIN: |
| rHomeBinSub= rHomeBin; |
| name= "R.exe"; //$NON-NLS-1$ |
| break; |
| default: |
| rHomeBinSub= rHomeBin.resolve("exec"); //$NON-NLS-1$ |
| name= "R"; //$NON-NLS-1$ |
| break; |
| } |
| final Path file= rHomeBinSub.resolve(rArch).resolve(name); |
| return Files.isRegularFile(file); |
| } |
| catch (final Exception e) { |
| return false; |
| } |
| } |
| |
| protected @Nullable Path getArchDirectory(final Path baseDirectory) { |
| String arch= this.config.getRArch(); |
| if (arch == null) { |
| arch= SystemUtils.getLocalArch(); |
| } |
| switch (arch) { |
| case SystemUtils.ARCH_X86_64: |
| return getFirstDirectory(baseDirectory, "x86_64", "x64"); //$NON-NLS-1$ //$NON-NLS-2$ |
| case SystemUtils.ARCH_X86_32: |
| return getFirstDirectory(baseDirectory, "x86", "i386", "i586", "i686"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| default: |
| return getFirstDirectory(baseDirectory, arch); |
| } |
| } |
| |
| protected List<Path> getRBinDirectoryCandidates() { |
| final List<Path> directories= new ArrayList<>(4); |
| |
| final Path rHomeBin= getRHomeDirectory().resolve("bin"); //$NON-NLS-1$ |
| final Path rHomeBinSub; |
| switch (SystemUtils.getLocalOs()) { |
| case OS_WIN: |
| rHomeBinSub= rHomeBin; |
| break; |
| default: // use wrapper shell scripts |
| rHomeBinSub= null; // rHomeBin.getChild("exec"); |
| break; |
| } |
| |
| if (rHomeBinSub != null) { |
| final Path rHomeBinArch= getArchDirectory(rHomeBinSub); |
| if (rHomeBinArch != null) { |
| directories.add(rHomeBinArch); |
| } |
| } |
| directories.add(rHomeBin); |
| |
| return directories; |
| } |
| |
| protected List<Path> getRLibDirectoryCandidates() { |
| final List<Path> directories= new ArrayList<>(4); |
| |
| final Path rHomeLib; |
| switch (SystemUtils.getLocalOs()) { |
| case OS_WIN: |
| rHomeLib= getRHomeDirectory().resolve("bin"); //$NON-NLS-1$ |
| break; |
| default: |
| rHomeLib= getRHomeDirectory().resolve("lib"); //$NON-NLS-1$ |
| break; |
| } |
| |
| if (SystemUtils.getLocalOs() != OS_MAC) { |
| final Path rHomeLibArch= getArchDirectory(rHomeLib); |
| if (rHomeLibArch != null) { |
| directories.add(rHomeLibArch); |
| } |
| } |
| directories.add(rHomeLib); |
| |
| return directories; |
| } |
| |
| private Path checkLibDirectory(final List<Path> candidates, final String fileName) |
| throws StatusException { |
| Path directory= getFirstDirectoryWith(getRLibDirectoryCandidates(), fileName); |
| if (directory == null) { |
| // TODO error? |
| REnvCoreInternals.log(new WarningStatus(REnvCoreInternals.BUNDLE_ID, |
| String.format("Could not find R library directory (file= '%1$s') for R environment '%2$s.", |
| fileName, this.config.getREnv().getId() ) )); |
| directory= candidates.get(candidates.size() - 1); |
| } |
| return directory; |
| } |
| |
| |
| protected @Nullable String getLibPathString(final @Nullable RLibGroup group) { |
| if (group == null) { |
| return null; |
| } |
| final List<? extends RLibLocation> libLocations= group.getLibLocations(); |
| if (libLocations.isEmpty()) { |
| return ""; //$NON-NLS-1$ |
| } |
| final StringBuilder sb= new StringBuilder(); |
| for (final RLibLocation lib : libLocations) { |
| final Path path= lib.getDirectoryPath(); |
| if (path != null) { |
| sb.append(toEnvVarString(path)); |
| } |
| sb.append(File.pathSeparatorChar); |
| } |
| return sb.substring(0, sb.length() - 1); |
| } |
| |
| |
| protected void putIfNonNull(final Map<String, String> envp, |
| final String name, final @Nullable Path path) { |
| if (path == null) { |
| return; |
| } |
| final String value= toEnvVarString(path); |
| envp.put(name, value); |
| } |
| |
| protected void putIfNonNull(final Map<String, String> envp, |
| final String name, final @Nullable String value) { |
| if (value == null) { |
| return; |
| } |
| envp.put(name, value); |
| } |
| |
| protected void putPrepend(final Map<String, String> envp, |
| final String name, final Path path) { |
| String value= toEnvVarString(path); |
| final String currentValue= getSystemEnvVar(name); |
| if (currentValue != null) { |
| value+= File.pathSeparatorChar + currentValue; |
| } |
| envp.put(name, value); |
| } |
| |
| protected String toEnvVarString(final Path path) { |
| return path.toString(); |
| } |
| |
| } |