diff options
author | Roland Grunberg | 2015-11-04 15:15:33 +0000 |
---|---|---|
committer | Roland Grunberg | 2015-11-19 15:49:07 +0000 |
commit | fd718c5f08046458acab7a889f1881cf200aba13 (patch) | |
tree | 4feeb94fd75117c946c3f8a0b345f8639e37959e /containers/org.eclipse.linuxtools.docker.core/src | |
parent | 9f8f13d4ca80a7f3828dcaf46cab536dbe9a23eb (diff) | |
download | org.eclipse.linuxtools-fd718c5f08046458acab7a889f1881cf200aba13.tar.gz org.eclipse.linuxtools-fd718c5f08046458acab7a889f1881cf200aba13.tar.xz org.eclipse.linuxtools-fd718c5f08046458acab7a889f1881cf200aba13.zip |
Bug 471672: Use a TM Terminal for containers with openStdin and tty.
Change-Id: Ifee8ab5ed99ad2419e3e1346899b5939f5b7f2e6
Reviewed-on: https://git.eclipse.org/r/59955
Tested-by: Hudson CI
Reviewed-by: Roland Grunberg <rgrunber@redhat.com>
Diffstat (limited to 'containers/org.eclipse.linuxtools.docker.core/src')
-rw-r--r-- | containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConnection.java | 199 |
1 files changed, 62 insertions, 137 deletions
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConnection.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConnection.java index 13c244b77c..386a92dec3 100644 --- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConnection.java +++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConnection.java @@ -63,6 +63,9 @@ import org.eclipse.linuxtools.docker.core.IDockerProgressHandler; import org.eclipse.linuxtools.docker.core.ILogger; import org.eclipse.linuxtools.docker.core.Messages; import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.terminal.view.core.TerminalServiceFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; import com.spotify.docker.client.ContainerNotFoundException; import com.spotify.docker.client.DefaultDockerClient; @@ -1275,7 +1278,7 @@ public class DockerConnection implements IDockerConnection, Closeable { } } - public WritableByteChannel attachCommand(final String id, + public void attachCommand(final String id, final InputStream in, final OutputStream out) throws DockerException { @@ -1285,7 +1288,33 @@ public class DockerConnection implements IDockerConnection, Closeable { AttachParameter.STDIN, AttachParameter.STDOUT, AttachParameter.STDERR, AttachParameter.STREAM, AttachParameter.LOGS); - final boolean isTtyEnabled = getContainerInfo(id).config().tty(); + final IDockerContainerInfo info = getContainerInfo(id); + final boolean isTtyEnabled = info.config().tty(); + final boolean isOpenStdin = info.config().openStdin(); + + if (isTtyEnabled) { + OutputStream tout = noBlockingOutputStream(HttpHijackWorkaround.getOutputStream(pty_stream, getUri())); + InputStream tin = HttpHijackWorkaround.getInputStream(pty_stream); + // org.eclipse.tm.terminal.connector.ssh.controls.SshWizardConfigurationPanel + Map<String, Object> properties = new HashMap<>(); + properties.put(ITerminalsConnectorConstants.PROP_DELEGATE_ID, "org.eclipse.tm.terminal.connector.streams.launcher.streams"); + properties.put(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID, "org.eclipse.tm.terminal.connector.streams.StreamsConnector"); + properties.put(ITerminalsConnectorConstants.PROP_TITLE, info.name()); + properties.put(ITerminalsConnectorConstants.PROP_LOCAL_ECHO, false); + properties.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, true); + properties.put(ITerminalsConnectorConstants.PROP_STREAMS_STDIN, tout); + properties.put(ITerminalsConnectorConstants.PROP_STREAMS_STDOUT, tin); + /* + * The JVM will call finalize() on 'pty_stream' (LogStream) + * since we hold no references to it (although we do hold + * references to one of its heavily nested fields. The + * LogStream overrides finalize() to close the stream being + * used so we must preserve a reference to it. + */ + properties.put("PREVENT_JVM_GC_FINALIZE", pty_stream); + ITerminalService service = TerminalServiceFactory.getService(); + service.openConsole(properties, null); + } // Data from the given input stream // Written to container's STDIN @@ -1312,147 +1341,14 @@ public class DockerConnection implements IDockerConnection, Closeable { } }); - t_in.start(); - // Incoming data from container's STDOUT - // Written to the given output stream - Thread t_out = new Thread(new Runnable() { - @Override - public void run() { - try { - InputStream pty_in = HttpHijackWorkaround - .getInputStream(pty_stream); - while (getContainerInfo(id).state().running()) { - byte[] buff = new byte[1024]; - int n = pty_in.read(buff); - if (n > 0) { - /* - * The container's STDOUT contains initial input - * we sent to its STDIN and the result. eg. > - * echo once < echo once \n $ once - * - * Try to remove this unwanted data from the - * stream. - */ - if (isTtyEnabled) { - int idex = 0; - synchronized (prevCmd) { - /* - * Check if buff contains a prefix of - * prevCmd ignoring differences in - * carriage return (10,13). Save the - * prefix's ending index. - */ - for (int i = 0; i < prevCmd.length; i++) { - if (prevCmd[i] != buff[i] - && (prevCmd[i] != 10 && buff[i] != 13) - && (prevCmd[i] != 13 && buff[i] != 10) - && prevCmd[i] != 0) { - idex = 0; - break; - } else if (prevCmd[i] != 0) { - idex++; - } - } - } - // A prefix exists, remove it - // Do not include the ending NL/CR - if (idex != 0) { - shiftLeft(buff, idex + 1); - } - n = removeTerminalCodes(buff); - } else { - /* - * If not in TTY mode, first 8 bytes are - * header data describing payload which we - * don't need. - */ - shiftLeft(buff, 8); - n = n - 8; - } - out.write(buff, 0, n); - } - } - } catch (Exception e) { - /* - * Temporary workaround for BZ #469717 - * Remove this when we begin using a release with : - * https://github.com/spotify/docker-client/pull/223 - */ - if (e instanceof SocketTimeoutException) { - try { - attachCommand(id, in, out); - } catch (DockerException e1) { - } - } - } - } - }); - - /* - * Our handling of STDOUT for terminals is mandatory, but the - * logging framework can handle catching output very early so use it - * for now. - */ - if (isTtyEnabled) { - t_out.start(); + if (!isTtyEnabled && isOpenStdin) { + t_in.start(); } - - return HttpHijackWorkaround.getOutputStream(pty_stream, getUri()); } catch (Exception e) { throw new DockerException(e.getMessage(), e.getCause()); } } - /* - * Incoming data from container's STDOUT contains terminal codes which the - * Eclipse Console does not support. Either we install/use some terminal - * plugin that does, or we need to remove these. - */ - private static int removeTerminalCodes(final byte[] buff) { - String tmp = new String(buff); - byte[] tmp_buff = tmp.replaceAll("\u001B]0;.*\u0007", "") - .replaceAll("\u001B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[mK]", "") - .replaceAll("\u001B\\[\\?[0-9]{1,4}h\\[", "").getBytes(); - for (int i = 0; i < buff.length; i++) { - if (i >= tmp_buff.length) { - buff[i] = 0; - } else { - buff[i] = tmp_buff[i]; - } - } - return getByteLength(buff); - } - - /* - * Shift contents of buff[idex] .. buff[buff.length-1] to buff[0] .. - * buff[(buff.length-1) - idex] - */ - private static void shiftLeft(byte[] buff, int idex) { - for (int i = 0; i < buff.length; i++) { - if (idex + i < buff.length) { - buff[i] = buff[idex + i]; - } else { - buff[i] = 0; - } - } - } - - /* - * Get the number of non-zero bytes from the beginning of the byte array. - */ - private static int getByteLength(byte[] buff) { - int n; - for (n = 0; n < buff.length; n++) { - if (buff[n] == 0) { - break; - } - } - if ((n == buff.length - 1) && buff[buff.length - 1] != 0) { - return buff.length; - } - return n; - } - @Override public String getTcpCertPath() { return tcpCertPath; @@ -1488,4 +1384,33 @@ public class DockerConnection implements IDockerConnection, Closeable { return name; } + public static OutputStream noBlockingOutputStream(final WritableByteChannel out) { + return new OutputStream() { + + @Override + public synchronized void write(int i) throws IOException { + byte b[] = new byte[1]; + b[0] = (byte) i; + write(b); + } + + @Override + public synchronized void write(byte[] b, int off, int len) + throws IOException { + if (len == 0) { + return; + } + ByteBuffer buff = ByteBuffer.wrap(b, off, len); + while (buff.remaining() > 0) { + out.write(buff); + } + } + + @Override + public void close() throws IOException { + out.close(); + } + }; + } + } |