| /*=============================================================================# |
| # Copyright (c) 2007, 2021 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.r.nico.impl; |
| |
| import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.lang.ProcessBuilder.Redirect; |
| import java.net.URL; |
| |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.ObjectUtils.ToStringBuilder; |
| import org.eclipse.statet.jcommons.runtime.ProcessUtils; |
| import org.eclipse.statet.jcommons.status.ProgressMonitor; |
| import org.eclipse.statet.jcommons.status.StatusException; |
| import org.eclipse.statet.jcommons.status.WarningStatus; |
| import org.eclipse.statet.jcommons.ts.core.Tool; |
| import org.eclipse.statet.jcommons.ts.core.ToolRunnable; |
| import org.eclipse.statet.jcommons.ts.core.ToolService; |
| |
| import org.eclipse.statet.internal.r.console.core.RConsoleCorePlugin; |
| import org.eclipse.statet.internal.r.nico.RNicoMessages; |
| import org.eclipse.statet.r.console.core.IRBasicAdapter; |
| import org.eclipse.statet.rj.renv.core.REnvConfiguration; |
| |
| |
| /** |
| * Cancel support for windows/rterm. |
| */ |
| @NonNullByDefault |
| class RTermCancelRunnable implements ToolRunnable { |
| |
| |
| RTermCancelRunnable() { |
| } |
| |
| |
| @Override |
| public String getLabel() { |
| return RNicoMessages.RTerm_CancelTask_label; |
| } |
| |
| @Override |
| @SuppressWarnings("null") |
| public String getTypeId() { |
| return null; // not a real runnable |
| } |
| |
| @Override |
| public boolean changed(final int event, final Tool process) { |
| return true; |
| } |
| |
| @Override |
| public boolean canRunIn(final Tool tool) { |
| return true; |
| } |
| |
| @Override |
| public void run(final ToolService service, final ProgressMonitor m) throws StatusException { |
| final IRBasicAdapter r= (IRBasicAdapter) service; |
| final REnvConfiguration rEnvConfig= nonNullAssert( |
| r.getTool().getAdapter(REnvConfiguration.class) ); |
| String arch= rEnvConfig.getRArch(); |
| if (arch == null) { |
| arch= Platform.getOSArch(); |
| } |
| try { |
| m.beginTask(RNicoMessages.RTerm_CancelTask_SendSignal_label, 10); |
| URL url= RConsoleCorePlugin.getInstance().getBundle().getEntry( |
| "/win32/" + arch + "/sendsignal.exe"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (url == null) { |
| throw new IOException("Missing 'sendsignal' tool for arch '" + arch + "'."); //$NON-NLS-1$ |
| } |
| url= FileLocator.toFileURL(url); |
| final File file= new File(url.getPath()); |
| if (!file.exists()) { |
| throw new IOException("Missing file '"+url.toExternalForm()+ "'."); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| m.addWorked(1); |
| final RTermController controller= (RTermController) r.getController(); |
| final Process rProcess= controller.getProcess(); |
| if (rProcess == null) { |
| return; |
| } |
| |
| final ProcessBuilder processBuilder= new ProcessBuilder( |
| file.getAbsolutePath(), Long.toString(rProcess.pid()) ); |
| processBuilder.redirectOutput(Redirect.DISCARD); |
| processBuilder.redirectErrorStream(true); |
| final Process process= processBuilder.start(); |
| m.addWorked(1); |
| while (true) { |
| try { |
| final int code= process.exitValue(); |
| if (code != 0) { |
| final ToStringBuilder detail= new ToStringBuilder("Command failed:"); |
| detail.addProp("command", //$NON-NLS-1$ |
| ProcessUtils.generateCommandLine(processBuilder.command()) ); |
| detail.addProp("os.name", //$NON-NLS-1$ |
| System.getProperty("os.name") ); //$NON-NLS-1$ |
| detail.addProp("os.version", //$NON-NLS-1$ |
| System.getProperty("os.version") ); //$NON-NLS-1$ |
| detail.addProp("os.arch", //$NON-NLS-1$ |
| System.getProperty("os.arch") ); //$NON-NLS-1$ |
| detail.addProp("r.arch", //$NON-NLS-1$ |
| arch ); |
| detail.addProp("exit.code", //$NON-NLS-1$ |
| "0x" + Integer.toHexString(code) ); |
| throw new IOException(detail.toString()); |
| } |
| break; |
| } |
| catch (final IllegalThreadStateException e) { |
| } |
| if (m.isCanceled()) { |
| process.destroy(); |
| RConsoleCorePlugin.log(new Status(IStatus.WARNING, RConsoleCorePlugin.BUNDLE_ID, -1, |
| "Sending CTRL+C to R process canceled.", null )); //$NON-NLS-1$ |
| break; |
| } |
| try { |
| Thread.sleep(50); |
| } |
| catch (final InterruptedException e) { |
| // continue directly |
| } |
| } |
| } |
| catch (final IOException e) { |
| throw new StatusException(new WarningStatus(RConsoleCorePlugin.BUNDLE_ID, |
| "Error Sending CTRL+C to R process.", |
| e )); |
| } |
| } |
| |
| } |