blob: ab06d625778e62bd7b4b9691362fbf0b42a9fd2a [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2005, 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.nico.core.runtime;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.IStatusHandler;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.osgi.util.NLS;
import org.eclipse.statet.jcommons.status.StatusException;
import org.eclipse.statet.jcommons.ts.core.Tool;
import org.eclipse.statet.internal.nico.core.Messages;
import org.eclipse.statet.internal.nico.core.NicoCorePlugin;
import org.eclipse.statet.nico.core.NicoCore;
/**
* Allows to run a ToolProcess in Eclipse.
*/
public class ToolRunner {
public static boolean captureLogOnly(final ILaunchConfiguration configuration) {
try {
return (!configuration.getAttribute("org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON", true) //$NON-NLS-1$
&& configuration.getAttribute("org.eclipse.debug.ui.ATTR_CAPTURE_IN_FILE", (String) null) == null ); //$NON-NLS-1$
}
catch (final CoreException e) {
return true;
}
}
public static IStatus createOutputLogStatus(final ILogOutput log) {
if (log != null) {
final String s = log.getOutput();
if (s.length() > 0) {
return new Status(IStatus.INFO, NicoCore.BUNDLE_ID, "Process Error Log:",
new Exception(s) );
}
}
return null;
}
private static class MultiErrorStatus extends Status {
private final IStatus[] children;
public MultiErrorStatus(final String pluginId, final int code,
final IStatus[] children, final String message, final Throwable exception) {
super(IStatus.ERROR, pluginId, code, message, exception);
this.children= children;
}
@Override
public boolean isMultiStatus() {
return true;
}
@Override
public IStatus[] getChildren() {
return this.children;
}
}
public ToolRunner() {
}
private void run(final ToolProcess process) throws StatusException {
final ToolController controller = process.getController();
controller.run();
}
public <WorkspaceType extends ToolWorkspace> void runInBackgroundThread(
final ToolProcess process, final IStatusHandler handler) {
if (process == null || handler == null) {
throw new NullPointerException();
}
final Thread background = new Thread() {
@Override
public void run() {
try {
ToolRunner.this.run(process);
}
catch (final StatusException e) {
if (e.getStatus() != null && e.getStatus().getSeverity() == IStatus.CANCEL) {
}
else {
process.setExitValue(NicoCore.EXITVALUE_CORE_EXCEPTION);
final IStatus status = createStatus(process,
NLS.bind(Messages.Runtime_error_UnexpectedTermination_message,
new Object[] { process.getLabel(Tool.DEFAULT_LABEL), process.getLabel() }),
e );
try {
handler.handleStatus(status, null);
}
catch (final CoreException e1) {
NicoCorePlugin.log(status);
NicoCorePlugin.logError(NicoCorePlugin.EXTERNAL_ERROR,
Messages.ErrorHandling_error_message, e1 );
}
}
}
catch (final Throwable e) {
// We had some problems with Thread#setUncaughtExceptionHandler, so we catch simply all Throwables
process.setExitValue(NicoCore.EXITVALUE_RUNTIME_EXCEPTION);
final IStatus status = createStatus(process,
NLS.bind(Messages.Runtime_error_CriticalError_message, getName()), e );
try {
handler.handleStatus(status, null);
}
catch (final CoreException e1) {
NicoCorePlugin.log(status);
NicoCorePlugin.logError(NicoCorePlugin.EXTERNAL_ERROR,
Messages.ErrorHandling_error_message, e1 );
}
final IStatus logStatus = createOutputLogStatus(process.getAdapter(ILogOutput.class));
if (logStatus != null) {
NicoCorePlugin.log(status);
}
}
try {
final ILaunch launch = process.getLaunch();
if (launch != null && !launch.isTerminated()) {
launch.isTerminated();
}
}
catch (final Throwable e) {}
}
};
background.setDaemon(true);
background.setName(process.getMainType() + " Engine '"+process.getLabel()+"'"); //$NON-NLS-1$ //$NON-NLS-2$
background.start();
}
private IStatus createStatus(final ToolProcess process, final String message, final Throwable e) {
final List<IStatus> list= new ArrayList<>();
final IProcess[] processes = process.getLaunch().getProcesses();
for (int i = 0; i < processes.length; i++) {
final IStatus logStatus = createOutputLogStatus(processes[i].getAdapter(ILogOutput.class));
if (logStatus != null) {
list.add(logStatus);
}
}
if (list.isEmpty()) {
return new Status(IStatus.ERROR, NicoCore.BUNDLE_ID, 0, message, e);
}
return new MultiErrorStatus(NicoCore.BUNDLE_ID, NicoCore.STATUSCODE_RUNTIME_ERROR,
list.toArray(new IStatus[list.size()]), message, e );
}
}