blob: 2da064df31070b12da58015a2e3004af8453a8ca [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2020 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Ansgar Radermacher ansgar.radermacher@cea.fr
*
*****************************************************************************/
package org.eclipse.papyrus.robotics.ros2.base;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.papyrus.designer.infra.base.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import com.google.common.collect.Lists;
/**
* Manage an environment for sub-processes
*/
public class EnvironmentUtils {
public static final String BASH_ENV = "BASH_ENV"; //$NON-NLS-1$
public static final String PATH = "PATH"; //$NON-NLS-1$
public static final String ROS_PREFIX = "ROS_"; //$NON-NLS-1$
public static final String DECLARE_X = "declare -x"; //$NON-NLS-1$
protected static Map<String, String> localEnv = null;
protected static Job setupJob;
/**
* @return an environment map
*/
public static Map<String, String> getenv() {
if (localEnv == null) {
localEnv = new HashMap<String, String>();
localEnv.putAll(System.getenv());
}
return localEnv;
}
/**
* Return an environment value from a key
*
* @param key
* @return the environment value
*/
public static String get(String key) {
return getenv().get(key);
}
// update the following environment values (and those starting with ROS_)
public static final List<String> checkValues = Lists.newArrayList(
Ros2Constants.CMAKE_PREFIX_PATH,
Ros2Constants.AMENT_PREFIX_PATH,
Ros2Constants.PYTHON_PATH,
"PATH", //$NON-NLS-1$
"LD_LIBRARY_PATH"); //$NON-NLS-1$
/**
* Run setup application in a new job
*/
public static void runCheckAndApplySetupJob(final String pathList) {
setupJob = new Job("check environment") { //$NON-NLS-1$
@Override
public IStatus run(IProgressMonitor monitor) {
boolean ok = EnvironmentUtils.checkAndApplySetup(pathList, monitor);
setupJob = null;
if (ok) {
return Status.OK_STATUS;
} else {
return Status.CANCEL_STATUS;
}
}
};
setupJob.schedule();
}
/**
* block, until an eventually running setup job is finished
*/
public static void waitForSetupJob() {
if (setupJob != null) {
try {
setupJob.join();
} catch (InterruptedException e) {
Activator.log.error(e);
}
}
}
/**
* Apply setup parameters
*
* @param pathList
* a colon (File.pathSeparator) separated list of setup paths
*/
@SuppressWarnings("nls")
public static boolean checkAndApplySetup(String pathList, IProgressMonitor monitor) {
if (pathList.length() == 0) {
// empty, nothing to do
return true;
}
String[] pathListArray = pathList.split(File.pathSeparator);
resetEnvironment();
monitor.beginTask("source setup.file", pathListArray.length);
for (String setupPath : pathListArray) {
String setupFile = setupPath + "/setup.bash"; //$NON-NLS-1$
monitor.subTask(setupFile);
if (new File(setupFile).exists()) {
sourceScript(setupFile);
} else {
// execute error message asynchronously to avoid blocking the tests (that run
// on an CI server without a ROS2 installation)
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
final Shell shell = Display.getCurrent().getActiveShell();
MessageDialog.openInformation(shell, "ROS setup", String.format( //$NON-NLS-1$
"Papyrus for Robotics could not find a setup.bash file at location (%s). " +
"Please verify the PATH in the ROS2 preferences.\n" +
"=> Window => Preferences => type \"ros\" in filter => setup path list.",
setupPath));
}
});
}
if (monitor.isCanceled()) {
return false;
}
monitor.worked(1);
}
return true;
}
/**
* reset the local environment variables back to the system values
*/
public static void resetEnvironment() {
if (localEnv != null) {
for (String var : System.getenv().keySet()) {
if (var.startsWith(ROS_PREFIX) || checkValues.contains(var)) {
String value = System.getenv(var);
localEnv.put(var, value);
}
}
}
}
@SuppressWarnings("nls")
public static void selectAndSourceScript(String initialFile, Shell shell) {
if (shell != null) {
FileDialog fd = new FileDialog(shell, SWT.OPEN);
fd.setText("Open");
String[] filterExt = { "*.bash;*.sh" };
String[] filterNames = { "setup files" };
fd.setFilterExtensions(filterExt);
fd.setFilterNames(filterNames);
fd.setFileName(initialFile);
String fileName = fd.open();
if (fileName != null) {
sourceScript(fileName);
}
}
}
/**
* Source the ROS2 setup.bash created within the Eclipse workspace
* (if it exists)
*/
public static void sourceWorkspace() {
String fileName = ResourcesPlugin.getWorkspace().getRoot().getLocation().toString();
fileName += "/install/setup.bash"; //$NON-NLS-1$
if (new File(fileName).exists()) {
sourceScript(fileName);
}
}
/**
* Source a ROS script and update the environment accordingly.
*
* @param scriptFile
*/
public static void sourceScript(String scriptFile) {
ProcessBuilder pb = new ProcessBuilder("bash", //$NON-NLS-1$
"-c", //$NON-NLS-1$
"export"); //$NON-NLS-1$
Map<String, String> pbEnv = pb.environment();
// the file in BASH_ENV is read by bash
pbEnv.put(BASH_ENV, scriptFile);
pbEnv.putAll(getenv());
try {
Process p = pb.start();
BufferedReader results = new BufferedReader(new InputStreamReader(p.getInputStream()));
boolean error = ProcessUtils.logErrors(p);
if (error) {
return;
}
String line;
// Map<String, String> env = EnvironmentUtils.getModifiableEnvironmentMap();
while ((line = results.readLine()) != null) {
line = line.substring(DECLARE_X.length());
String lineArray[] = line.split("="); //$NON-NLS-1$
if (lineArray.length == 2) {
String var = lineArray[0].trim();
String value = StringUtils.unquote(lineArray[1]);
if (var.startsWith(ROS_PREFIX) || checkValues.contains(var)) {
localEnv.put(var, value);
}
}
}
} catch (Exception e) {
Activator.log.error(e);
}
}
/**
* Return the executable or null
*
* @param executable
* the name of the executable
* @return the absolute path to the executable or null
*/
public static String getFromPath(final String executable) {
String path = get(PATH);
if (path != null) {
String[] pathParts = path.split(File.pathSeparator);
for (String pathPart : pathParts) {
File file = new File(pathPart + File.separator + executable);
if (file.exists()) {
return file.getAbsolutePath();
}
}
}
return null;
}
}