Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Grunberg2015-11-04 15:15:33 +0000
committerRoland Grunberg2015-11-19 15:49:07 +0000
commitfd718c5f08046458acab7a889f1881cf200aba13 (patch)
tree4feeb94fd75117c946c3f8a0b345f8639e37959e /containers
parent9f8f13d4ca80a7f3828dcaf46cab536dbe9a23eb (diff)
downloadorg.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')
-rw-r--r--containers/org.eclipse.linuxtools.docker.core/META-INF/MANIFEST.MF3
-rw-r--r--containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConnection.java199
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/RunConsole.java127
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/CommandUtils.java5
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/DisplayContainerLogCommandHandler.java11
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RunImageCommandHandler.java7
6 files changed, 104 insertions, 248 deletions
diff --git a/containers/org.eclipse.linuxtools.docker.core/META-INF/MANIFEST.MF b/containers/org.eclipse.linuxtools.docker.core/META-INF/MANIFEST.MF
index 4a97886814..301847808a 100644
--- a/containers/org.eclipse.linuxtools.docker.core/META-INF/MANIFEST.MF
+++ b/containers/org.eclipse.linuxtools.docker.core/META-INF/MANIFEST.MF
@@ -17,7 +17,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.10.0",
javax.ws.rs;bundle-version="2.0.1",
org.glassfish.jersey.core.jersey-client;bundle-version="2.14.0",
org.glassfish.jersey.media.jersey-media-json-jackson;bundle-version="2.14.0",
- org.glassfish.jersey.core.jersey-common;bundle-version="2.14.0"
+ org.glassfish.jersey.core.jersey-common;bundle-version="2.14.0",
+ org.eclipse.tm.terminal.view.core;bundle-version="4.0.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy
Export-Package: org.eclipse.linuxtools.docker.core,
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();
+ }
+ };
+ }
+
}
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/RunConsole.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/RunConsole.java
index 37a76cac2c..2542eab450 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/RunConsole.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/RunConsole.java
@@ -14,30 +14,19 @@ package org.eclipse.linuxtools.internal.docker.ui;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.WritableByteChannel;
-import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.linuxtools.docker.core.IDockerConnection;
import org.eclipse.linuxtools.docker.core.IDockerContainer;
import org.eclipse.linuxtools.internal.docker.core.DockerConnection;
import org.eclipse.linuxtools.internal.docker.ui.views.DVMessages;
-import org.eclipse.swt.custom.StyledText;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
-import org.eclipse.ui.console.IConsoleView;
import org.eclipse.ui.console.IOConsole;
-import org.eclipse.ui.console.TextConsole;
-import org.eclipse.ui.internal.console.IOConsolePage;
-import org.eclipse.ui.part.IPageBookViewPage;
/**
* RpmConsole is used to output rpm/rpmbuild output.
*
*/
-@SuppressWarnings("restriction")
public class RunConsole extends IOConsole {
/** Id of this console. */
@@ -50,7 +39,6 @@ public class RunConsole extends IOConsole {
private OutputStream outputStream;
private boolean attached = false;
- private final WritableByteChannel[] ptyOutRef = new WritableByteChannel[1];
/**
* Returns a reference to the console that is for the given container id. If
@@ -135,11 +123,6 @@ public class RunConsole extends IOConsole {
return ret;
}
- @Override
- public IPageBookViewPage createPage(IConsoleView view) {
- return new RunConsolePage(this, view);
- }
-
/**
* Set the title of the RunConsole
*
@@ -170,11 +153,7 @@ public class RunConsole extends IOConsole {
.running()) {
Thread.sleep(1000);
}
- WritableByteChannel pty_out = conn
- .attachCommand(containerId, in, out);
- if (conn.getContainerInfo(containerId).config().tty()) {
- ptyOutRef[0] = pty_out;
- }
+ conn.attachCommand(containerId, in, out);
}
} catch (Exception e) {
}
@@ -184,6 +163,27 @@ public class RunConsole extends IOConsole {
attached = true;
}
+ public static void attachToTerminal (final IDockerConnection connection, final String containerId) {
+ Thread t = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ DockerConnection conn = (DockerConnection) connection;
+ if (conn.getContainerInfo(containerId).config()
+ .openStdin()) {
+ while (!conn.getContainerInfo(containerId).state()
+ .running()) {
+ Thread.sleep(1000);
+ }
+ conn.attachCommand(containerId, null, null);
+ }
+ } catch (Exception e) {
+ }
+ }
+ });
+ t.start();
+ }
+
public void attachToConsole(final IDockerConnection connection,
String containerId) {
this.containerId = containerId;
@@ -263,87 +263,4 @@ public class RunConsole extends IOConsole {
this.containerId = containerId;
this.id = id;
}
-
- /*
- * Custom Page used to add our own set of actions.
- */
- private class RunConsolePage extends IOConsolePage {
-
- public RunConsolePage(TextConsole console, IConsoleView view) {
- super(console, view);
- }
-
- @Override
- protected void configureToolBar(IToolBarManager mgr) {
- super.configureToolBar(mgr);
-
- if (getControl() != null && getControl() instanceof StyledText) {
- StyledText styledText = (StyledText) getControl();
- styledText.addKeyListener(new TTYKeyListener());
- }
- }
-
- }
-
- /*
- * Listener to support sending certain key sequences
- */
- private class TTYKeyListener implements KeyListener {
- private boolean isCtrlOn;
-
- private final int CTRL_CODE = 262144;
- private final int C_CODE = 'c';
- private final int TAB_CODE = 9;
-
- public TTYKeyListener() {
- this.isCtrlOn = false;
- }
-
- @Override
- public void keyReleased(KeyEvent e) {
- if (ptyOutRef[0] != null && ptyOutRef[0].isOpen()) {
- WritableByteChannel pty_out = ptyOutRef[0];
- try {
- switch (e.keyCode) {
- case CTRL_CODE:
- isCtrlOn = false;
- break;
- case TAB_CODE:
- pty_out.write(
- ByteBuffer.wrap(new byte[] { 9, 9 }, 0, 2));
- break;
- }
- } catch (IOException e1) {
- }
- }
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- if (ptyOutRef[0] != null && ptyOutRef[0].isOpen()) {
- WritableByteChannel pty_out = ptyOutRef[0];
- try {
- switch (e.keyCode) {
- /*
- * TODO : These values are configurable, so we should
- * start using 'stty -a' to know what they really are.
- */
- case C_CODE:
- // ETX (End Of Text) (3) is usually the interrupt
- // signal.
- if (isCtrlOn) {
- pty_out.write(
- ByteBuffer.wrap(new byte[] { 3 }, 0, 1));
- }
- break;
- case CTRL_CODE:
- isCtrlOn = true;
- break;
- }
- } catch (IOException e1) {
- }
- }
- }
- }
-
}
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/CommandUtils.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/CommandUtils.java
index 7bc47a087b..7077d8e729 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/CommandUtils.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/CommandUtils.java
@@ -193,8 +193,13 @@ public class CommandUtils {
* @return the {@link RunConsole} or {@code null}
*/
public static RunConsole getRunConsole(final IDockerConnection connection, final IDockerContainer container) {
+ if (connection.getContainerInfo(container.id()).config().tty()) {
+ RunConsole.attachToTerminal(connection, container.id());
+ return null;
+ }
final boolean autoLogOnStart = Activator.getDefault().getPreferenceStore()
.getBoolean(PreferenceConstants.AUTOLOG_ON_START);
+
// if we are auto-logging, grab the
// console for the container id and get
// its stream.
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/DisplayContainerLogCommandHandler.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/DisplayContainerLogCommandHandler.java
index 0cfb4179dc..64df9e4565 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/DisplayContainerLogCommandHandler.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/DisplayContainerLogCommandHandler.java
@@ -46,12 +46,17 @@ public class DisplayContainerLogCommandHandler extends AbstractHandler {
final IDockerContainer container = selectedContainers.get(0);
final String id = container.id();
final String name = container.name();
+
+ if (connection.getContainerInfo(id).config().tty()) {
+ RunConsole.attachToTerminal(connection, id);
+ return null;
+ }
try {
final RunConsole rc = RunConsole.findConsole(id);
- if (!rc.isAttached()) {
- rc.attachToConsole(connection);
- }
if (rc != null) {
+ if (!rc.isAttached()) {
+ rc.attachToConsole(connection);
+ }
Display.getDefault().syncExec(new Runnable() {
@Override
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RunImageCommandHandler.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RunImageCommandHandler.java
index 4c8530869c..f4c151caa5 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RunImageCommandHandler.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/RunImageCommandHandler.java
@@ -134,9 +134,12 @@ public class RunImageCommandHandler extends AbstractHandler {
if (console != null) {
// if we are auto-logging, show the console
console.showConsole();
+ ((DockerConnection) connection).startContainer(
+ containerId, console.getOutputStream());
+ } else {
+ ((DockerConnection) connection)
+ .startContainer(containerId, null);
}
- ((DockerConnection) connection).startContainer(containerId,
- console.getOutputStream());
startContainerMonitor.done();
} catch (final DockerException | InterruptedException e) {
Display.getDefault().syncExec(new Runnable() {

Back to the top