IDEA-CR-48777: PY-34633 Python docker-compose: support debugger for Python Console and Docker for Mac

(cherry picked from commit 12640e452f8a17fe63ae9adf4fd31620ebba80a6)

GitOrigin-RevId: 3002704426b9e086f5939d8b0c9ff7d22e234edb
This commit is contained in:
Vladimir Lagunov
2019-07-04 09:02:24 +03:00
committed by intellij-monorepo-bot
parent b2d163b65a
commit c9260bd5be
6 changed files with 147 additions and 37 deletions
@@ -7,7 +7,7 @@
package com.jetbrains.python.console.protocol;
@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2019-05-07")
@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)")
public class PythonConsoleBackendService {
public interface Iface {
@@ -58,7 +58,7 @@ public class PythonConsoleBackendService {
*/
public void changeVariable(java.lang.String evaluationExpression, java.lang.String value) throws org.apache.thrift.TException;
public void connectToDebugger(int localPort, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs) throws org.apache.thrift.TException;
public void connectToDebugger(int localPort, java.lang.String host, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs) throws org.apache.thrift.TException;
public void interrupt() throws org.apache.thrift.TException;
@@ -102,7 +102,7 @@ public class PythonConsoleBackendService {
public void changeVariable(java.lang.String evaluationExpression, java.lang.String value, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
public void connectToDebugger(int localPort, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
public void connectToDebugger(int localPort, java.lang.String host, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
public void interrupt(org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
@@ -297,16 +297,17 @@ public class PythonConsoleBackendService {
return;
}
public void connectToDebugger(int localPort, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs) throws org.apache.thrift.TException
public void connectToDebugger(int localPort, java.lang.String host, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs) throws org.apache.thrift.TException
{
send_connectToDebugger(localPort, opts, extraEnvs);
send_connectToDebugger(localPort, host, opts, extraEnvs);
recv_connectToDebugger();
}
public void send_connectToDebugger(int localPort, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs) throws org.apache.thrift.TException
public void send_connectToDebugger(int localPort, java.lang.String host, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs) throws org.apache.thrift.TException
{
connectToDebugger_args args = new connectToDebugger_args();
args.setLocalPort(localPort);
args.setHost(host);
args.setOpts(opts);
args.setExtraEnvs(extraEnvs);
sendBase("connectToDebugger", args);
@@ -694,20 +695,22 @@ public class PythonConsoleBackendService {
}
}
public void connectToDebugger(int localPort, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException {
public void connectToDebugger(int localPort, java.lang.String host, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException {
checkReady();
connectToDebugger_call method_call = new connectToDebugger_call(localPort, opts, extraEnvs, resultHandler, this, ___protocolFactory, ___transport);
connectToDebugger_call method_call = new connectToDebugger_call(localPort, host, opts, extraEnvs, resultHandler, this, ___protocolFactory, ___transport);
this.___currentMethod = method_call;
___manager.call(method_call);
}
public static class connectToDebugger_call extends org.apache.thrift.async.TAsyncMethodCall<Void> {
private int localPort;
private java.lang.String host;
private java.util.Map<java.lang.String,java.lang.Boolean> opts;
private java.util.Map<java.lang.String,java.lang.String> extraEnvs;
public connectToDebugger_call(int localPort, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
public connectToDebugger_call(int localPort, java.lang.String host, java.util.Map<java.lang.String,java.lang.Boolean> opts, java.util.Map<java.lang.String,java.lang.String> extraEnvs, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
super(client, protocolFactory, transport, resultHandler, false);
this.localPort = localPort;
this.host = host;
this.opts = opts;
this.extraEnvs = extraEnvs;
}
@@ -716,6 +719,7 @@ public class PythonConsoleBackendService {
prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("connectToDebugger", org.apache.thrift.protocol.TMessageType.CALL, 0));
connectToDebugger_args args = new connectToDebugger_args();
args.setLocalPort(localPort);
args.setHost(host);
args.setOpts(opts);
args.setExtraEnvs(extraEnvs);
args.write(prot);
@@ -1160,7 +1164,7 @@ public class PythonConsoleBackendService {
public connectToDebugger_result getResult(I iface, connectToDebugger_args args) throws org.apache.thrift.TException {
connectToDebugger_result result = new connectToDebugger_result();
iface.connectToDebugger(args.localPort, args.opts, args.extraEnvs);
iface.connectToDebugger(args.localPort, args.host, args.opts, args.extraEnvs);
return result;
}
}
@@ -1834,7 +1838,7 @@ public class PythonConsoleBackendService {
}
public void start(I iface, connectToDebugger_args args, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException {
iface.connectToDebugger(args.localPort, args.opts, args.extraEnvs,resultHandler);
iface.connectToDebugger(args.localPort, args.host, args.opts, args.extraEnvs,resultHandler);
}
}
@@ -7396,21 +7400,24 @@ public class PythonConsoleBackendService {
private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("connectToDebugger_args");
private static final org.apache.thrift.protocol.TField LOCAL_PORT_FIELD_DESC = new org.apache.thrift.protocol.TField("localPort", org.apache.thrift.protocol.TType.I32, (short)1);
private static final org.apache.thrift.protocol.TField OPTS_FIELD_DESC = new org.apache.thrift.protocol.TField("opts", org.apache.thrift.protocol.TType.MAP, (short)2);
private static final org.apache.thrift.protocol.TField EXTRA_ENVS_FIELD_DESC = new org.apache.thrift.protocol.TField("extraEnvs", org.apache.thrift.protocol.TType.MAP, (short)3);
private static final org.apache.thrift.protocol.TField HOST_FIELD_DESC = new org.apache.thrift.protocol.TField("host", org.apache.thrift.protocol.TType.STRING, (short)2);
private static final org.apache.thrift.protocol.TField OPTS_FIELD_DESC = new org.apache.thrift.protocol.TField("opts", org.apache.thrift.protocol.TType.MAP, (short)3);
private static final org.apache.thrift.protocol.TField EXTRA_ENVS_FIELD_DESC = new org.apache.thrift.protocol.TField("extraEnvs", org.apache.thrift.protocol.TType.MAP, (short)4);
private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new connectToDebugger_argsStandardSchemeFactory();
private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new connectToDebugger_argsTupleSchemeFactory();
public int localPort; // required
public java.lang.String host; // required
public java.util.Map<java.lang.String,java.lang.Boolean> opts; // required
public java.util.Map<java.lang.String,java.lang.String> extraEnvs; // required
/** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
public enum _Fields implements org.apache.thrift.TFieldIdEnum {
LOCAL_PORT((short)1, "localPort"),
OPTS((short)2, "opts"),
EXTRA_ENVS((short)3, "extraEnvs");
HOST((short)2, "host"),
OPTS((short)3, "opts"),
EXTRA_ENVS((short)4, "extraEnvs");
private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
@@ -7427,9 +7434,11 @@ public class PythonConsoleBackendService {
switch(fieldId) {
case 1: // LOCAL_PORT
return LOCAL_PORT;
case 2: // OPTS
case 2: // HOST
return HOST;
case 3: // OPTS
return OPTS;
case 3: // EXTRA_ENVS
case 4: // EXTRA_ENVS
return EXTRA_ENVS;
default:
return null;
@@ -7478,6 +7487,8 @@ public class PythonConsoleBackendService {
java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
tmpMap.put(_Fields.LOCAL_PORT, new org.apache.thrift.meta_data.FieldMetaData("localPort", org.apache.thrift.TFieldRequirementType.DEFAULT,
new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
tmpMap.put(_Fields.HOST, new org.apache.thrift.meta_data.FieldMetaData("host", org.apache.thrift.TFieldRequirementType.DEFAULT,
new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
tmpMap.put(_Fields.OPTS, new org.apache.thrift.meta_data.FieldMetaData("opts", org.apache.thrift.TFieldRequirementType.DEFAULT,
new org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP,
new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING),
@@ -7495,12 +7506,14 @@ public class PythonConsoleBackendService {
public connectToDebugger_args(
int localPort,
java.lang.String host,
java.util.Map<java.lang.String,java.lang.Boolean> opts,
java.util.Map<java.lang.String,java.lang.String> extraEnvs)
{
this();
this.localPort = localPort;
setLocalPortIsSet(true);
this.host = host;
this.opts = opts;
this.extraEnvs = extraEnvs;
}
@@ -7511,6 +7524,9 @@ public class PythonConsoleBackendService {
public connectToDebugger_args(connectToDebugger_args other) {
__isset_bitfield = other.__isset_bitfield;
this.localPort = other.localPort;
if (other.isSetHost()) {
this.host = other.host;
}
if (other.isSetOpts()) {
java.util.Map<java.lang.String,java.lang.Boolean> __this__opts = new java.util.HashMap<java.lang.String,java.lang.Boolean>(other.opts);
this.opts = __this__opts;
@@ -7529,6 +7545,7 @@ public class PythonConsoleBackendService {
public void clear() {
setLocalPortIsSet(false);
this.localPort = 0;
this.host = null;
this.opts = null;
this.extraEnvs = null;
}
@@ -7556,6 +7573,30 @@ public class PythonConsoleBackendService {
__isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __LOCALPORT_ISSET_ID, value);
}
public java.lang.String getHost() {
return this.host;
}
public connectToDebugger_args setHost(java.lang.String host) {
this.host = host;
return this;
}
public void unsetHost() {
this.host = null;
}
/** Returns true if field host is set (has been assigned a value) and false otherwise */
public boolean isSetHost() {
return this.host != null;
}
public void setHostIsSet(boolean value) {
if (!value) {
this.host = null;
}
}
public int getOptsSize() {
return (this.opts == null) ? 0 : this.opts.size();
}
@@ -7636,6 +7677,14 @@ public class PythonConsoleBackendService {
}
break;
case HOST:
if (value == null) {
unsetHost();
} else {
setHost((java.lang.String)value);
}
break;
case OPTS:
if (value == null) {
unsetOpts();
@@ -7660,6 +7709,9 @@ public class PythonConsoleBackendService {
case LOCAL_PORT:
return getLocalPort();
case HOST:
return getHost();
case OPTS:
return getOpts();
@@ -7679,6 +7731,8 @@ public class PythonConsoleBackendService {
switch (field) {
case LOCAL_PORT:
return isSetLocalPort();
case HOST:
return isSetHost();
case OPTS:
return isSetOpts();
case EXTRA_ENVS:
@@ -7711,6 +7765,15 @@ public class PythonConsoleBackendService {
return false;
}
boolean this_present_host = true && this.isSetHost();
boolean that_present_host = true && that.isSetHost();
if (this_present_host || that_present_host) {
if (!(this_present_host && that_present_host))
return false;
if (!this.host.equals(that.host))
return false;
}
boolean this_present_opts = true && this.isSetOpts();
boolean that_present_opts = true && that.isSetOpts();
if (this_present_opts || that_present_opts) {
@@ -7738,6 +7801,10 @@ public class PythonConsoleBackendService {
hashCode = hashCode * 8191 + localPort;
hashCode = hashCode * 8191 + ((isSetHost()) ? 131071 : 524287);
if (isSetHost())
hashCode = hashCode * 8191 + host.hashCode();
hashCode = hashCode * 8191 + ((isSetOpts()) ? 131071 : 524287);
if (isSetOpts())
hashCode = hashCode * 8191 + opts.hashCode();
@@ -7767,6 +7834,16 @@ public class PythonConsoleBackendService {
return lastComparison;
}
}
lastComparison = java.lang.Boolean.valueOf(isSetHost()).compareTo(other.isSetHost());
if (lastComparison != 0) {
return lastComparison;
}
if (isSetHost()) {
lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.host, other.host);
if (lastComparison != 0) {
return lastComparison;
}
}
lastComparison = java.lang.Boolean.valueOf(isSetOpts()).compareTo(other.isSetOpts());
if (lastComparison != 0) {
return lastComparison;
@@ -7811,6 +7888,14 @@ public class PythonConsoleBackendService {
sb.append(this.localPort);
first = false;
if (!first) sb.append(", ");
sb.append("host:");
if (this.host == null) {
sb.append("null");
} else {
sb.append(this.host);
}
first = false;
if (!first) sb.append(", ");
sb.append("opts:");
if (this.opts == null) {
sb.append("null");
@@ -7879,7 +7964,15 @@ public class PythonConsoleBackendService {
org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
}
break;
case 2: // OPTS
case 2: // HOST
if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
struct.host = iprot.readString();
struct.setHostIsSet(true);
} else {
org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
}
break;
case 3: // OPTS
if (schemeField.type == org.apache.thrift.protocol.TType.MAP) {
{
org.apache.thrift.protocol.TMap _map64 = iprot.readMapBegin();
@@ -7899,7 +7992,7 @@ public class PythonConsoleBackendService {
org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
}
break;
case 3: // EXTRA_ENVS
case 4: // EXTRA_ENVS
if (schemeField.type == org.apache.thrift.protocol.TType.MAP) {
{
org.apache.thrift.protocol.TMap _map68 = iprot.readMapBegin();
@@ -7937,6 +8030,11 @@ public class PythonConsoleBackendService {
oprot.writeFieldBegin(LOCAL_PORT_FIELD_DESC);
oprot.writeI32(struct.localPort);
oprot.writeFieldEnd();
if (struct.host != null) {
oprot.writeFieldBegin(HOST_FIELD_DESC);
oprot.writeString(struct.host);
oprot.writeFieldEnd();
}
if (struct.opts != null) {
oprot.writeFieldBegin(OPTS_FIELD_DESC);
{
@@ -7984,16 +8082,22 @@ public class PythonConsoleBackendService {
if (struct.isSetLocalPort()) {
optionals.set(0);
}
if (struct.isSetOpts()) {
if (struct.isSetHost()) {
optionals.set(1);
}
if (struct.isSetExtraEnvs()) {
if (struct.isSetOpts()) {
optionals.set(2);
}
oprot.writeBitSet(optionals, 3);
if (struct.isSetExtraEnvs()) {
optionals.set(3);
}
oprot.writeBitSet(optionals, 4);
if (struct.isSetLocalPort()) {
oprot.writeI32(struct.localPort);
}
if (struct.isSetHost()) {
oprot.writeString(struct.host);
}
if (struct.isSetOpts()) {
{
oprot.writeI32(struct.opts.size());
@@ -8019,12 +8123,16 @@ public class PythonConsoleBackendService {
@Override
public void read(org.apache.thrift.protocol.TProtocol prot, connectToDebugger_args struct) throws org.apache.thrift.TException {
org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
java.util.BitSet incoming = iprot.readBitSet(3);
java.util.BitSet incoming = iprot.readBitSet(4);
if (incoming.get(0)) {
struct.localPort = iprot.readI32();
struct.setLocalPortIsSet(true);
}
if (incoming.get(1)) {
struct.host = iprot.readString();
struct.setHostIsSet(true);
}
if (incoming.get(2)) {
{
org.apache.thrift.protocol.TMap _map76 = new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.BOOL, iprot.readI32());
struct.opts = new java.util.HashMap<java.lang.String,java.lang.Boolean>(2*_map76.size);
@@ -8039,7 +8147,7 @@ public class PythonConsoleBackendService {
}
struct.setOptsIsSet(true);
}
if (incoming.get(2)) {
if (incoming.get(3)) {
{
org.apache.thrift.protocol.TMap _map80 = new org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRING, org.apache.thrift.protocol.TType.STRING, iprot.readI32());
struct.extraEnvs = new java.util.HashMap<java.lang.String,java.lang.String>(2*_map80.size);
@@ -451,7 +451,7 @@ class BaseInterpreterInterface(BaseCodeExecutor):
else:
return self.orig_find_frame(thread_id, frame_id)
def connectToDebugger(self, debuggerPort, debugger_options=None, extra_envs=None):
def connectToDebugger(self, debuggerPort, debugger_host=None, debugger_options=None, extra_envs=None):
'''
Used to show console with variables connection.
Mainly, monkey-patches things in the debugger structure so that the debugger protocol works.
@@ -490,7 +490,7 @@ class BaseInterpreterInterface(BaseCodeExecutor):
self.debugger = pydevd.PyDB()
try:
pydevd.apply_debugger_options(debugger_options)
self.debugger.connect(pydev_localhost.get_localhost(), debuggerPort)
self.debugger.connect(debugger_host or pydev_localhost.get_localhost(), debuggerPort)
self.debugger.prepare_to_run()
self.debugger.disable_tracing()
except:
@@ -153,7 +153,7 @@ service PythonConsoleBackendService {
*/
void changeVariable(1: string evaluationExpression, 2: string value),
void connectToDebugger(1: i32 localPort, 2: map<string, bool> opts, 3: map<string, string> extraEnvs),
void connectToDebugger(1: i32 localPort, 2: string host, 3: map<string, bool> opts, 4: map<string, string> extraEnvs),
void interrupt(),
@@ -19,6 +19,7 @@ import com.google.common.collect.Maps;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.remote.RemoteProcessControl;
import com.intellij.util.ui.UIUtil;
import com.intellij.xdebugger.XDebugSession;
@@ -82,17 +83,17 @@ public class PyConsoleDebugProcess extends PyDebugProcess {
}
public void connect(PydevConsoleCommunication consoleCommunication) throws Exception {
int portToConnect;
Pair<String, Integer> portToConnect;
if (myConsoleDebugProcessHandler.getConsoleProcessHandler() instanceof RemoteProcessControl) {
portToConnect = getRemoteTunneledPort(myLocalPort,
((RemoteProcessControl)myConsoleDebugProcessHandler.getConsoleProcessHandler()));
portToConnect = getRemoteHostPortForDebuggerConnection(myLocalPort,
((RemoteProcessControl)myConsoleDebugProcessHandler.getConsoleProcessHandler()));
}
else {
portToConnect = myLocalPort;
portToConnect = Pair.create("localhost", myLocalPort);
}
Map<String, Boolean> optionsMap = makeDebugOptionsMap(getSession());
Map<String, String> envs = getDebuggerEnvs(getSession());
consoleCommunication.connectToDebugger(portToConnect, optionsMap, envs);
consoleCommunication.connectToDebugger(portToConnect.getSecond(), portToConnect.getFirst(), optionsMap, envs);
}
public static Map<String, String> getDebuggerEnvs(XDebugSession session) {
@@ -636,14 +636,14 @@ public abstract class PydevConsoleCommunication extends AbstractConsoleCommunica
* @param extraEnvs
* @throws Exception if connection fails
*/
public void connectToDebugger(int localPort, @NotNull Map<String, Boolean> dbgOpts, @NotNull Map<String, String> extraEnvs)
public void connectToDebugger(int localPort, @Nullable String debuggerHost, @NotNull Map<String, Boolean> dbgOpts, @NotNull Map<String, String> extraEnvs)
throws Exception {
if (waitingForInput) {
throw new Exception("Can't connect debugger now, waiting for input");
}
try {
// though `connectToDebugger` returns "connect complete" string, let us just ignore it
getPythonConsoleBackendClient().connectToDebugger(localPort, dbgOpts, extraEnvs);
getPythonConsoleBackendClient().connectToDebugger(localPort, debuggerHost, dbgOpts, extraEnvs);
}
catch (CommunicationClosedException | PyConsoleProcessFinishedException | TException e) {
throw new PyDebuggerException("pydevconsole failed to execute connectToDebugger", e);
@@ -337,16 +337,17 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
@Override
public int handleDebugPort(int localPort) throws IOException {
if (myProcessHandler instanceof RemoteProcessControl) {
return getRemoteTunneledPort(localPort, (RemoteProcessControl)myProcessHandler);
return getRemoteHostPortForDebuggerConnection(localPort, (RemoteProcessControl)myProcessHandler).getSecond();
}
else {
return localPort;
}
}
protected static int getRemoteTunneledPort(int localPort, @NotNull RemoteProcessControl handler) throws IOException {
protected static Pair<String, Integer> getRemoteHostPortForDebuggerConnection(int localPort, @NotNull RemoteProcessControl handler)
throws IOException {
try {
return handler.getRemoteSocket(localPort).getSecond();
return handler.getRemoteSocket(localPort);
}
catch (Exception e) {
throw new IOException(e);