blob: c0bbf4ea263cb44a0e18435899915786619e24a4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.launching;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.dltk.compiler.util.Util;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.environment.IEnvironment;
import org.eclipse.dltk.core.environment.IExecutionEnvironment;
import org.eclipse.dltk.core.environment.IExecutionLogger;
import org.eclipse.dltk.core.environment.IFileHandle;
import org.eclipse.dltk.internal.launching.DLTKLaunchingPlugin;
import org.eclipse.dltk.internal.launching.InterpreterMessages;
import org.eclipse.osgi.util.NLS;
import com.ibm.icu.text.DateFormat;
/**
* Abstract implementation of a interpreter runner.
* <p>
* Clients implementing interpreter runners should subclass this class.
* </p>
*
* @see IInterpreterRunner
*
*/
public abstract class AbstractInterpreterRunner implements IInterpreterRunner {
private IInterpreterInstall interpreterInstall;
protected IInterpreterInstall getInstall() {
return interpreterInstall;
}
private static String renderProcessLabel(String[] commandLine) {
String format = LaunchingMessages.StandardInterpreterRunner;
String timestamp = DateFormat
.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM)
.format(new Date(System.currentTimeMillis()));
return NLS.bind(format, commandLine[0], timestamp);
}
/**
* String representation of the command line
*
* @param commandLine
* @return
*/
private static String renderCommandLineLabel(String[] commandLine) {
if (commandLine.length == 0)
return Util.EMPTY_STRING;
StringBuffer buf = new StringBuffer();
for (int i = 0; i < commandLine.length; i++) {
if (i != 0) {
buf.append(' ');
}
char[] characters = commandLine[i].toCharArray();
StringBuffer command = new StringBuffer();
boolean containsSpace = false;
for (int j = 0; j < characters.length; j++) {
char character = characters[j];
if (character == '\"') {
command.append('\\');
} else if (character == ' ') {
containsSpace = true;
}
command.append(character);
}
if (containsSpace) {
buf.append('\"');
buf.append(command.toString());
buf.append('\"');
} else {
buf.append(command.toString());
}
}
return buf.toString();
}
protected String renderCommandLineLabel(InterpreterConfig config) {
String[] cmdLine = renderCommandLine(config);
return renderCommandLineLabel(cmdLine);
}
protected void abort(String message, Throwable exception)
throws CoreException {
throw new CoreException(
new Status(IStatus.ERROR, DLTKLaunchingPlugin.PLUGIN_ID,
ScriptLaunchConfigurationConstants.ERR_INTERNAL_ERROR,
message, exception));
}
protected void abort(String message, Throwable exception, int code)
throws CoreException {
throw new CoreException(new Status(IStatus.ERROR,
DLTKLaunchingPlugin.PLUGIN_ID, code, message, exception));
}
// Execution helpers
// protected Process exec(String[] cmdLine, File workingDirectory)
// throws CoreException {
// return DebugPlugin.exec(cmdLine, workingDirectory);
// }
//
protected Map<String, String> getDefaultProcessMap() {
Map<String, String> map = new HashMap<>();
map.put(IProcess.ATTR_PROCESS_TYPE, getProcessType());
return map;
}
protected String getProcessType() {
return ScriptLaunchConfigurationConstants.ID_SCRIPT_PROCESS_TYPE;
}
protected AbstractInterpreterRunner(IInterpreterInstall install) {
this.interpreterInstall = install;
}
protected void checkConfig(InterpreterConfig config,
IEnvironment environment) throws CoreException {
IPath workingDirectoryPath = config.getWorkingDirectoryPath();
IFileHandle dir = environment.getFile(workingDirectoryPath);
if (!dir.exists()) {
abort(NLS.bind(
InterpreterMessages.errDebuggingEngineWorkingDirectoryDoesntExist,
dir.toString()), null);
}
if (config.getScriptFilePath() == null) {
return;
}
if (!config.isNoFile()) {
final IFileHandle script = environment
.getFile(config.getScriptFilePath());
if (!script.exists()) {
abort(NLS.bind(
InterpreterMessages.errDebuggingEngineScriptFileDoesntExist,
script.toString()), null);
}
}
}
/**
* Returns a new process aborting if the process could not be created.
*
* @param launch
* the launch the process is contained in
* @param p
* the system process to wrap
* @param label
* the label assigned to the process
* @param attributes
* values for the attribute map
* @return the new process
* @throws CoreException
* problems occurred creating the process
* @since 2.0
*
*/
protected IProcess newProcess(ILaunch launch, Process p, String label,
Map<String, String> attributes) throws CoreException {
IProcess process = DebugPlugin.newProcess(launch, p, label, attributes);
if (process == null) {
p.destroy();
abort(LaunchingMessages.AbstractInterpreterRunner_0, null);
}
return process;
}
protected String[] renderCommandLine(InterpreterConfig config) {
return config.renderCommandLine(interpreterInstall);
}
protected IProcess rawRun(final ILaunch launch, InterpreterConfig config)
throws CoreException {
checkConfig(config, getInstall().getEnvironment());
String[] cmdLine = renderCommandLine(config);
IPath workingDirectory = config.getWorkingDirectoryPath();
String[] environment = getEnvironmentVariablesAsStrings(config);
final String cmdLineLabel = renderCommandLineLabel(cmdLine);
final String processLabel = renderProcessLabel(cmdLine);
if (DLTKLaunchingPlugin.TRACE_EXECUTION) {
traceExecution(processLabel, cmdLineLabel, workingDirectory,
environment);
}
IExecutionEnvironment exeEnv = interpreterInstall.getExecEnvironment();
IExecutionLogger logger = DLTKLaunchingPlugin.LOGGING_CATCH_OUTPUT
.isEnabled() ? new LaunchLogger() : null;
Process p = exeEnv.exec(cmdLine, workingDirectory, environment, logger);
if (p == null) {
abort(LaunchingMessages.AbstractInterpreterRunner_executionWasCancelled,
null);
}
launch.setAttribute(DLTKLaunchingPlugin.LAUNCH_COMMAND_LINE,
cmdLineLabel);
final IProcess process[] = new IProcess[] { null };
DebugPlugin.getDefault()
.addDebugEventListener(new IDebugEventSetListener() {
@Override
public void handleDebugEvents(DebugEvent[] events) {
for (int i = 0; i < events.length; i++) {
DebugEvent event = events[i];
if (event.getSource().equals(process[0])) {
if (event.getKind() == DebugEvent.CHANGE
|| event.getKind() == DebugEvent.TERMINATE) {
updateProcessLabel(launch, cmdLineLabel,
process[0]);
if (event
.getKind() == DebugEvent.TERMINATE) {
DebugPlugin.getDefault()
.removeDebugEventListener(this);
}
}
}
}
}
});
process[0] = newProcess(launch, p, processLabel,
getDefaultProcessMap());
process[0].setAttribute(IProcess.ATTR_CMDLINE, cmdLineLabel);
updateProcessLabel(launch, cmdLineLabel, process[0]);
return process[0];
}
private void updateProcessLabel(final ILaunch launch,
final String cmdLineLabel, final IProcess process) {
StringBuffer buffer = new StringBuffer();
int exitValue = 0;
try {
exitValue = process.getExitValue();
} catch (DebugException e1) {
// DLTKCore.error(e1);
exitValue = 0;// Seems not available yet
}
if (exitValue != 0) {
buffer.append("<abnormal exit code:" + exitValue + "> ");
}
String type = null;
ILaunchConfiguration launchConfiguration = launch
.getLaunchConfiguration();
if (launchConfiguration != null) {
try {
ILaunchConfigurationType launchConfigType = launchConfiguration
.getType();
if (launchConfigType != null) {
type = launchConfigType.getName();
}
} catch (CoreException e) {
DLTKCore.error(e);
}
buffer.append(launchConfiguration.getName());
}
if (type != null) {
buffer.append(" ["); //$NON-NLS-1$
buffer.append(type);
buffer.append("] "); //$NON-NLS-1$
}
buffer.append(process.getLabel());
process.setAttribute(IProcess.ATTR_PROCESS_LABEL, buffer.toString());
}
/**
* @since 2.0
*/
protected String[] getEnvironmentVariablesAsStrings(
InterpreterConfig config) {
return config.getEnvironmentAsStringsIncluding(
getInstall().getEnvironmentVariables());
}
private void traceExecution(String processLabel, String cmdLineLabel,
IPath workingDirectory, String[] environment) {
StringBuffer sb = new StringBuffer();
sb.append("-----------------------------------------------\n"); //$NON-NLS-1$
sb.append("Running ").append(processLabel).append('\n'); //$NON-NLS-1$
sb.append("Command line: ").append(cmdLineLabel).append('\n'); //$NON-NLS-1$
sb.append("Working directory: ").append(workingDirectory).append('\n'); //$NON-NLS-1$
sb.append("Environment:\n"); //$NON-NLS-1$
for (int i = 0; i < environment.length; i++) {
sb.append('\t').append(environment[i]).append('\n');
}
sb.append("-----------------------------------------------\n"); //$NON-NLS-1$
System.out.println(sb);
}
@Override
public void run(InterpreterConfig config, ILaunch launch,
IProgressMonitor monitor) throws CoreException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
try {
monitor.beginTask(
LaunchingMessages.AbstractInterpreterRunner_launching, 5);
if (monitor.isCanceled()) {
return;
}
alterConfig(launch, config);
monitor.worked(1);
monitor.subTask(
LaunchingMessages.AbstractInterpreterRunner_running);
rawRun(launch, config);
monitor.worked(4);
} finally {
monitor.done();
}
}
protected void alterConfig(ILaunch launch, InterpreterConfig config) {
}
}