diff --git a/java/execution/impl/src/com/intellij/execution/application/BaseJavaApplicationCommandLineState.java b/java/execution/impl/src/com/intellij/execution/application/BaseJavaApplicationCommandLineState.java index 1fe13ae33580..7aa8c4bb4e36 100644 --- a/java/execution/impl/src/com/intellij/execution/application/BaseJavaApplicationCommandLineState.java +++ b/java/execution/impl/src/com/intellij/execution/application/BaseJavaApplicationCommandLineState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,13 +22,11 @@ import com.intellij.execution.RunConfigurationExtension; import com.intellij.execution.configurations.JavaCommandLineState; import com.intellij.execution.configurations.JavaParameters; import com.intellij.execution.configurations.RunConfigurationBase; -import com.intellij.execution.configurations.RunnerSettings; import com.intellij.execution.process.KillableColoredProcessHandler; import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.process.ProcessTerminatedListener; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.util.JavaParametersUtil; -import com.intellij.openapi.util.SystemInfo; import org.jetbrains.annotations.NotNull; /** @@ -53,17 +51,9 @@ public abstract class BaseJavaApplicationCommandLineState + * Soft kill works on Unix, and also on Windows if a mediator process was used. + * * @author Roman.Chernyatchik - *

- * This process handler supports ANSI coloring and soft-kill feature. Soft kill works only on Unix. - * At first "stop" button send SIGINT signal to process, if it still hangs user can termintate it recursively with SIGKILL signal. - *

- * P.S: probably OSProcessHandler is better place for this feature but it can affect other run configurations and should be tested */ public class KillableColoredProcessHandler extends ColoredProcessHandler implements KillableProcess { - private static final Logger LOG = Logger.getInstance(KillableColoredProcessHandler .class); + private static final Logger LOG = Logger.getInstance(KillableColoredProcessHandler.class); + private static final Key MEDIATOR_KEY = Key.create("KillableColoredProcessHandler.Mediator.Process"); private boolean myShouldKillProcessSoftly = true; + private boolean myMediatedProcess = false; public KillableColoredProcessHandler(@NotNull GeneralCommandLine commandLine) throws ExecutionException { super(commandLine); } - public KillableColoredProcessHandler(final Process process, final String commandLine, @NotNull final Charset charset) { + /** + * Starts a process with a {@link RunnerMediator mediator} when {@code withMediator} is set to {@code true} and the platform is Windows. + */ + public KillableColoredProcessHandler(@NotNull GeneralCommandLine commandLine, boolean withMediator) throws ExecutionException { + super(mediate(commandLine, withMediator).createProcess(), commandLine.getCommandLineString(), commandLine.getCharset()); + myMediatedProcess = withMediator && MEDIATOR_KEY.get(commandLine) == Boolean.TRUE; + } + + public KillableColoredProcessHandler(@NotNull Process process, @Nullable String commandLine) { + super(process, commandLine); + } + + public KillableColoredProcessHandler(@NotNull Process process, @Nullable String commandLine, @NotNull Charset charset) { super(process, commandLine, charset); } - public KillableColoredProcessHandler(final Process process, final String commandLine) { - super(process, commandLine); + private static GeneralCommandLine mediate(GeneralCommandLine commandLine, boolean withMediator) { + if (withMediator && SystemInfo.isWindows) { + boolean mediatorInjected = RunnerMediator.injectRunnerCommand(commandLine); + MEDIATOR_KEY.set(commandLine, mediatorInjected); + } + return commandLine; + } + + /** + * @return true, if graceful process termination should be attempted first + */ + protected boolean shouldKillProcessSoftly() { + return myShouldKillProcessSoftly; } /** * Sets whether the process will be terminated gracefully. + * * @param shouldKillProcessSoftly true, if graceful process termination should be attempted first (i.e. soft kill) */ public void setShouldKillProcessSoftly(boolean shouldKillProcessSoftly) { @@ -60,14 +88,12 @@ public class KillableColoredProcessHandler extends ColoredProcessHandler impleme /** * This method shouldn't be overridden, see shouldKillProcessSoftly - * - * @return */ private boolean canKillProcessSoftly() { if (processCanBeKilledByOS(myProcess)) { if (SystemInfo.isWindows) { // runnerw.exe can send Ctrl+C events to a wrapped process - return myProcess instanceof RunnerWinProcess; + return myMediatedProcess; } else if (SystemInfo.isUnix) { // 'kill -SIGINT ' will be executed @@ -104,10 +130,7 @@ public class KillableColoredProcessHandler extends ColoredProcessHandler impleme @Override protected void doDestroyProcess() { - boolean gracefulTerminationAttempted = false; - if (canKillProcessSoftly() && shouldKillProcessSoftly()) { - gracefulTerminationAttempted = destroyProcessGracefully(); - } + boolean gracefulTerminationAttempted = shouldKillProcessSoftly() && canKillProcessSoftly() && destroyProcessGracefully(); if (!gracefulTerminationAttempted) { // execute default process destroy super.doDestroyProcess(); @@ -115,12 +138,8 @@ public class KillableColoredProcessHandler extends ColoredProcessHandler impleme } protected boolean destroyProcessGracefully() { - if (SystemInfo.isWindows) { - if (myProcess instanceof RunnerWinProcess) { - RunnerWinProcess runnerWinProcess = (RunnerWinProcess) myProcess; - runnerWinProcess.destroyGracefully(true); - return true; - } + if (SystemInfo.isWindows && myMediatedProcess) { + return RunnerMediator.destroyProcess(myProcess, true); } else if (SystemInfo.isUnix) { return UnixProcessManager.sendSigIntToProcessTree(myProcess); @@ -128,13 +147,6 @@ public class KillableColoredProcessHandler extends ColoredProcessHandler impleme return false; } - /** - * @return true, if graceful process termination should be attempted first - */ - protected boolean shouldKillProcessSoftly() { - return myShouldKillProcessSoftly; - } - @Override public boolean canKillProcess() { return processCanBeKilledByOS(getProcess()); @@ -146,18 +158,9 @@ public class KillableColoredProcessHandler extends ColoredProcessHandler impleme killProcessTree(getProcess()); } - @NotNull + /** @deprecated use {@link #KillableColoredProcessHandler(GeneralCommandLine, boolean)} (to be removed in IDEA 17) */ + @SuppressWarnings("unused") public static KillableColoredProcessHandler create(@NotNull GeneralCommandLine commandLine) throws ExecutionException { - final Process process; - if (SystemInfo.isWindows) { - process = RunnerWinProcess.create(commandLine); - } - else { - process = commandLine.createProcess(); - } - return new KillableColoredProcessHandler(process, - commandLine.getCommandLineString(), - commandLine.getCharset()); + return new KillableColoredProcessHandler(commandLine, true); } - } diff --git a/platform/platform-impl/src/com/intellij/execution/process/RunnerMediator.java b/platform/platform-impl/src/com/intellij/execution/process/RunnerMediator.java index 649835c3a544..dae3b75060fd 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/RunnerMediator.java +++ b/platform/platform-impl/src/com/intellij/execution/process/RunnerMediator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,9 @@ import java.io.OutputStream; import java.io.PrintWriter; /** + * Utility class to start a process with a runner mediator (runnerw.exe) injected into a command line, + * which adds a capability to terminate process tree gracefully by sending it a Ctrl+Break through stdin. + * * @author traff */ public class RunnerMediator { @@ -147,19 +150,14 @@ public class RunnerMediator { public static class CustomDestroyProcessHandler extends ColoredProcessHandler { private final boolean mySoftKill; - /** - * @deprecated use CustomDestroyProcessHandler(GeneralCommandLine commandLine) - * @deprecated remove in IDEA 16 - */ + /** @deprecated use CustomDestroyProcessHandler(GeneralCommandLine commandLine) (to remove in IDEA 16) */ public CustomDestroyProcessHandler(@NotNull Process process, @NotNull GeneralCommandLine commandLine) { - this(process, commandLine, false); + super(process, commandLine.getCommandLineString()); + mySoftKill = false; } - /** - * @deprecated use CustomDestroyProcessHandler(GeneralCommandLine commandLine, boolean softKill) - * @deprecated remove in IDEA 16 - */ - public CustomDestroyProcessHandler(@NotNull Process process, @NotNull GeneralCommandLine commandLine, final boolean softKill) { + /** @deprecated use CustomDestroyProcessHandler(GeneralCommandLine commandLine, boolean softKill) (to remove in IDEA 16) */ + public CustomDestroyProcessHandler(@NotNull Process process, @NotNull GeneralCommandLine commandLine, boolean softKill) { super(process, commandLine.getCommandLineString()); mySoftKill = softKill; } diff --git a/platform/platform-impl/src/com/intellij/execution/process/RunnerWinProcess.java b/platform/platform-impl/src/com/intellij/execution/process/RunnerWinProcess.java index 833591c75ce0..30910579ad0a 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/RunnerWinProcess.java +++ b/platform/platform-impl/src/com/intellij/execution/process/RunnerWinProcess.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,8 @@ import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.util.SystemInfo; import org.jetbrains.annotations.NotNull; +/** @deprecated use {@link KillableColoredProcessHandler#KillableColoredProcessHandler(GeneralCommandLine, boolean)} (to be removed in IDEA 16) */ +@SuppressWarnings({"unused", "deprecation"}) public class RunnerWinProcess extends ProcessWrapper { private RunnerWinProcess(@NotNull Process originalProcess) { @@ -37,7 +39,7 @@ public class RunnerWinProcess extends ProcessWrapper { @NotNull public static Process create(@NotNull GeneralCommandLine commandLine) throws ExecutionException { if (!SystemInfo.isWindows) { - throw new RuntimeException(RunnerWinProcess.class.getSimpleName() + " works on Windows only!"); + throw new RuntimeException("RunnerWinProcess works on Windows only!"); } boolean success = RunnerMediator.injectRunnerCommand(commandLine); Process process = commandLine.createProcess(); diff --git a/platform/platform-impl/src/com/intellij/execution/process/impl/OSProcessManagerImpl.java b/platform/platform-impl/src/com/intellij/execution/process/impl/OSProcessManagerImpl.java index 8aa35eb05ffa..5cfa088922f3 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/impl/OSProcessManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/execution/process/impl/OSProcessManagerImpl.java @@ -57,12 +57,10 @@ public class OSProcessManagerImpl extends OSProcessManager { return false; } + @SuppressWarnings("deprecation") @NotNull private static WinProcess createWinProcess(@NotNull Process process) { - if (process instanceof RunnerWinProcess) { - RunnerWinProcess runnerWinProcess = (RunnerWinProcess) process; - return new WinProcess(runnerWinProcess.getOriginalProcess()); - } + if (process instanceof RunnerWinProcess) process = ((RunnerWinProcess)process).getOriginalProcess(); return new WinProcess(process); }