Bug 521211 - Docker launch fails debugging some C/C++ programs
- using normal logging doesn't always work when debugging via gdbserver
(e.g. a program that printfs without a newline and then uses
an fflush of stdout)
- add a new DockerConsoleOutputStream class to core that will
accept listeners that will be notified whenever writes are made
- change openTerminal method in DockerConnection to accept a
DockerConsoleOutputStream as input parameter and to use this
to echo stdout and stderr output of the terminal
- change RunConsole.attachTerminal method to accept a
DockerConsoleOutputStream argument
- change ContainerLauncher launch method to determine when
called to do a gdbserver launch from CDT (look at
ContainerListener class name)
- when it is determined that we are doing a gdbserver launch,
set the TTY option on and pass a DockerConsoleOutput stream
to RunConsole.attachTerminal which will pass this on to
openTerminal
- set up the DockerConsoleOutputStream to echo output to the
normal RunConsole used for running and debugging
- when the session is complete, remove any Terminal that was
created on behalf of the session
- change all callers of RunConsole.attachTerminal appropriately
to pass null as last argument
- remove ConsoleOutputStream from docker ui
Change-Id: I17758f1ed9f0af6df754af88570cc4b7767c9638
Reviewed-on: https://git.eclipse.org/r/103419
Tested-by: Hudson CI
Reviewed-by: Jeff Johnston <jjohnstn@redhat.com>
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 4831fe9..e8eaaae 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
@@ -89,6 +89,7 @@
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.ITerminalServiceOutputStreamMonitorListener;
import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants;
import com.google.common.collect.ImmutableMap;
@@ -581,6 +582,7 @@
getContainers(force);
} catch (DockerException e) {
Activator.log(e);
+ return Collections.emptyList();
}
} else if (!isContainersLoaded() || force) {
@@ -984,6 +986,7 @@
latestImages = getImages(force);
} catch (DockerException e) {
Activator.log(e);
+ return Collections.emptyList();
}
} else if (!isImagesLoaded() || force) {
try {
@@ -1933,7 +1936,6 @@
Activator.log(e);
}
}
-
}
@Override
@@ -2007,7 +2009,7 @@
}
public void attachCommand(final String id, final InputStream in,
- @SuppressWarnings("unused") final OutputStream out)
+ @SuppressWarnings("unused") final DockerConsoleOutputStream out)
throws DockerException {
final byte[] prevCmd = new byte[1024];
@@ -2021,7 +2023,7 @@
final boolean isOpenStdin = info.config().openStdin();
if (isTtyEnabled) {
- openTerminal(pty_stream, info.name());
+ openTerminal(pty_stream, info.name(), out);
}
// Data from the given input stream
@@ -2130,16 +2132,43 @@
final LogStream pty_stream = client.execStart(execId,
DockerClient.ExecStartParameter.TTY);
final IDockerContainerInfo info = getContainerInfo(id);
- openTerminal(pty_stream, info.name() + " [shell]"); //$NON-NLS-1$
+ openTerminal(pty_stream, info.name() + " [shell]", null); //$NON-NLS-1$
} catch (Exception e) {
throw new DockerException(e.getMessage(), e.getCause());
}
}
- private void openTerminal(LogStream pty_stream, String name) throws DockerException {
+ private class TerminalOutputMonitorListener
+ implements ITerminalServiceOutputStreamMonitorListener {
+
+ private DockerConsoleOutputStream consoleOutputStream;
+
+ public TerminalOutputMonitorListener(DockerConsoleOutputStream out) {
+ this.consoleOutputStream = out;
+ }
+
+ @Override
+ public void onContentReadFromStream(byte[] byteBuffer, int bytesRead) {
+ try {
+ if (consoleOutputStream != null) {
+ consoleOutputStream.write(byteBuffer, 0, bytesRead);
+ }
+ } catch (IOException e) {
+ Activator.log(e);
+ }
+ }
+
+ }
+
+ private void openTerminal(LogStream pty_stream, String name,
+ DockerConsoleOutputStream out) throws DockerException {
try {
- OutputStream tout = noBlockingOutputStream(HttpHijackWorkaround.getOutputStream(pty_stream, getUri()));
+ OutputStream tout = noBlockingOutputStream(
+ HttpHijackWorkaround.getOutputStream(pty_stream, getUri()));
InputStream tin = HttpHijackWorkaround.getInputStream(pty_stream);
+
+ TerminalOutputMonitorListener monitor = new TerminalOutputMonitorListener(out);
+
// org.eclipse.tm.terminal.connector.ssh.controls.SshWizardConfigurationPanel
Map<String, Object> properties = new HashMap<>();
properties.put(ITerminalsConnectorConstants.PROP_DELEGATE_ID,
@@ -2152,6 +2181,10 @@
properties.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, true);
properties.put(ITerminalsConnectorConstants.PROP_STREAMS_STDIN, tout);
properties.put(ITerminalsConnectorConstants.PROP_STREAMS_STDOUT, tin);
+ properties.put(ITerminalsConnectorConstants.PROP_STDERR_LISTENERS, new ITerminalServiceOutputStreamMonitorListener[] {monitor});
+ properties.put(ITerminalsConnectorConstants.PROP_STDOUT_LISTENERS,
+ new ITerminalServiceOutputStreamMonitorListener[] {
+ monitor });
properties.put(ITerminalsConnectorConstants.PROP_DATA, pty_stream);
/*
* The JVM will call finalize() on 'pty_stream' (LogStream)
@@ -2161,6 +2194,10 @@
* used so we must preserve a reference to it.
*/
properties.put("PREVENT_JVM_GC_FINALIZE", pty_stream); //$NON-NLS-1$
+ // save properties to remove terminal later
+ if (out != null) {
+ out.setTerminalProperties(properties);
+ }
ITerminalService service = TerminalServiceFactory.getService();
service.openConsole(properties, null);
} catch (Exception e) {
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConsoleOutputStream.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConsoleOutputStream.java
new file mode 100644
index 0000000..e2c1d27
--- /dev/null
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerConsoleOutputStream.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 Red Hat.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Red Hat - Initial Contribution
+ *******************************************************************************/
+package org.eclipse.linuxtools.internal.docker.core;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Map;
+
+import org.eclipse.core.runtime.ListenerList;
+
+// Special Console OutputStream which supports listeners.
+
+public class DockerConsoleOutputStream extends OutputStream {
+
+ private OutputStream stream;
+ private Map<String, Object> properties;
+
+ ListenerList<IConsoleListener> consoleListeners;
+
+ public DockerConsoleOutputStream(OutputStream stream) {
+ this.stream = stream;
+ }
+
+ public DockerConsoleOutputStream setOutputStream(OutputStream stream) {
+ this.stream = stream;
+ return this;
+ }
+
+ public void setTerminalProperties(Map<String, Object> properties) {
+ this.properties = properties;
+ }
+
+ public Map<String, Object> getTerminalProperties() {
+ return properties;
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ if (stream != null) {
+ stream.write(b);
+ }
+ notifyConsoleListeners(b, 0, b.length);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (stream != null) {
+ stream.write(b, off, len);
+ }
+ notifyConsoleListeners(b, off, len);
+ }
+
+ @Override
+ public void write(int arg0) throws IOException {
+ byte[] b = new byte[1];
+ b[0] = (byte) arg0;
+ write(b);
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (stream != null) {
+ stream.close();
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (stream != null) {
+ stream.flush();
+ }
+ }
+
+ public void addConsoleListener(IConsoleListener listener) {
+ if (consoleListeners == null)
+ consoleListeners = new ListenerList<>(ListenerList.IDENTITY);
+ consoleListeners.add(listener);
+ }
+
+ public void removeConsoleListener(IConsoleListener listener) {
+ if (consoleListeners != null)
+ consoleListeners.remove(listener);
+ }
+
+ public void notifyConsoleListeners(byte[] b, int off, int len) {
+ if (consoleListeners != null) {
+ String output = new String(b, off, len);
+ Object[] listeners = consoleListeners.getListeners();
+ for (int i = 0; i < listeners.length; ++i) {
+ ((IConsoleListener) listeners[i]).newOutput(output);
+ }
+ }
+ }
+
+}
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/IConsoleListener.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/IConsoleListener.java
new file mode 100644
index 0000000..2b3cff9
--- /dev/null
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/IConsoleListener.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 Red Hat.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Red Hat - Initial Contribution
+ *******************************************************************************/
+package org.eclipse.linuxtools.internal.docker.core;
+
+public interface IConsoleListener {
+
+ /**
+ * Listener receiver method called after output is written to Console.
+ *
+ * @param output
+ * string written to console
+ */
+ void newOutput(String output);
+
+}
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/launch/ContainerLauncher.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/launch/ContainerLauncher.java
index c5ea7e0..cc745da 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/launch/ContainerLauncher.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/docker/ui/launch/ContainerLauncher.java
@@ -48,7 +48,6 @@
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.linuxtools.docker.core.DockerConnectionManager;
import org.eclipse.linuxtools.docker.core.DockerException;
-import org.eclipse.linuxtools.docker.core.EnumDockerLoggingStatus;
import org.eclipse.linuxtools.docker.core.IDockerConnection;
import org.eclipse.linuxtools.docker.core.IDockerContainerConfig;
import org.eclipse.linuxtools.docker.core.IDockerContainerExit;
@@ -59,16 +58,22 @@
import org.eclipse.linuxtools.docker.core.IDockerPortBinding;
import org.eclipse.linuxtools.docker.ui.Activator;
import org.eclipse.linuxtools.internal.docker.core.DockerConnection;
+import org.eclipse.linuxtools.internal.docker.core.DockerConsoleOutputStream;
import org.eclipse.linuxtools.internal.docker.core.DockerContainerConfig;
import org.eclipse.linuxtools.internal.docker.core.DockerHostConfig;
import org.eclipse.linuxtools.internal.docker.core.DockerPortBinding;
+import org.eclipse.linuxtools.internal.docker.core.IConsoleListener;
import org.eclipse.linuxtools.internal.docker.ui.consoles.ConsoleOutputStream;
import org.eclipse.linuxtools.internal.docker.ui.consoles.RunConsole;
import org.eclipse.linuxtools.internal.docker.ui.launch.ContainerCommandProcess;
import org.eclipse.linuxtools.internal.docker.ui.launch.LaunchConfigurationUtils;
import org.eclipse.linuxtools.internal.docker.ui.views.DVMessages;
import org.eclipse.linuxtools.internal.docker.ui.wizards.DataVolumeModel;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
public class ContainerLauncher {
@@ -545,6 +550,25 @@
}
+ // The following class allows us to use internal IConsoleListeners in
+ // docker.core
+ // but still use the public IRunConsoleListeners API here without requiring
+ // a minor release.
+ private class RunConsoleListenerBridge implements IConsoleListener {
+
+ private IRunConsoleListener listener;
+
+ public RunConsoleListenerBridge(IRunConsoleListener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void newOutput(String output) {
+ listener.newOutput(output);
+ }
+
+ }
+
/**
* Perform a launch of a command in a container and output stdout/stderr to
* console.
@@ -652,6 +676,17 @@
.cmd(cmdList)
.image(image)
.workingDir(workingDir);
+
+ // Ugly hack...we want CDT gdbserver to run in the terminal so we look
+ // for its
+ // ContainerListener class and set tty=true in that case...this avoids a
+ // minor release and we can later add a new launch method with the tty
+ // option
+ if (listener != null && listener.getClass().getName().equals(
+ "org.eclipse.cdt.internal.docker.launcher.ContainerLaunchConfigurationDelegate$StartGdbServerJob")) {
+ builder = builder.tty(true);
+ }
+
// add any exposed ports as needed
if (exposedPorts.size() > 0)
builder = builder.exposedPorts(exposedPorts);
@@ -776,77 +811,163 @@
return;
}
}
- OutputStream stream = null;
- RunConsole oldConsole = getConsole();
- final RunConsole rc = RunConsole.findConsole(containerId,
- consoleId);
- setConsole(rc);
- rc.clearConsole();
- if (oldConsole != null)
- RunConsole.removeConsole(oldConsole);
- Display.getDefault()
- .syncExec(() -> rc.setTitle(Messages.getFormattedString(
- LAUNCH_TITLE, new String[] { cmdList.get(0),
- imageName })));
- // if (!rc.isAttached()) {
- rc.attachToConsole(connection, containerId);
- // }
- if (rc != null) {
- stream = rc.getOutputStream();
- if (containerListener != null) {
- ((ConsoleOutputStream) stream)
- .addConsoleListener(containerListener);
+ if (config.tty()) {
+ // We need tty support to handle issue with Docker daemon
+ // not always outputting in time (e.g. we might get an
+ // output line after the process has exited which can be
+ // too late to show or it might get displayed in a wrong
+ // order in relation to other output. We also want the
+ // output to ultimately show up in the Console View.
+ OutputStream stream = null;
+ RunConsole oldConsole = getConsole();
+ final RunConsole rc = RunConsole.findConsole(containerId,
+ consoleId);
+ setConsole(rc);
+ rc.clearConsole();
+ if (oldConsole != null)
+ RunConsole.removeConsole(oldConsole);
+ Display.getDefault().syncExec(() -> rc.setTitle(Messages
+ .getFormattedString(LAUNCH_TITLE, new String[] {
+ cmdList.get(0), imageName })));
+ if (rc != null) {
+ stream = rc.getOutputStream();
}
- }
- // Create a unique logging thread id which has container id
- // and console id
- String loggingId = containerId + "." + consoleId;
- ((DockerConnection) connection).startContainer(containerId,
- loggingId, stream);
- if (rc != null)
- rc.showConsole();
- if (containerListener != null) {
+
+ // We want terminal support, but we want to output to the
+ // RunConsole.
+ // To do this, we create a DockerConsoleOutputStream which
+ // we
+ // hook into the TM Terminal via stdout and stderr output
+ // listeners.
+ // These listeners will output to the
+ // DockerConsoleOutputStream which
+ // will in turn output to the RunConsole. See
+ // DockerConnection.openTerminal().
+ DockerConsoleOutputStream out = new DockerConsoleOutputStream(
+ stream);
+ RunConsole.attachToTerminal(connection, containerId, out);
+ if (containerListener != null) {
+ out.addConsoleListener(new RunConsoleListenerBridge(
+ containerListener));
+ }
+ ((DockerConnection) connection).startContainer(containerId,
+ null, null);
IDockerContainerInfo info = ((DockerConnection) connection)
.getContainerInfo(containerId);
- containerListener.containerInfo(info);
- }
-
- // Wait for the container to finish
- final IDockerContainerExit status = ((DockerConnection) connection)
- .waitForContainer(containerId);
- Display.getDefault().syncExec(() -> {
- rc.setTitle(
- Messages.getFormattedString(LAUNCH_EXITED_TITLE,
- new String[] {
- status.statusCode().toString(),
- cmdList.get(0), imageName }));
- rc.showConsole();
- });
-
- // Let any container listener know that the container is
- // finished
- if (containerListener != null)
- containerListener.done();
-
- if (!keepContainer) {
- // Drain the logging thread before we remove the
- // container (we need to use the logging id)
- ((DockerConnection) connection)
- .stopLoggingThread(loggingId);
- while (((DockerConnection) connection).loggingStatus(
- loggingId) == EnumDockerLoggingStatus.LOGGING_ACTIVE) {
- Thread.sleep(1000);
+ if (containerListener != null) {
+ containerListener.containerInfo(info);
}
- // Look for any Display Log console that the user may
- // have opened which would be
- // separate and make sure it is removed as well
- RunConsole rc2 = RunConsole
- .findConsole(((DockerConnection) connection)
- .getContainer(containerId));
- if (rc2 != null)
- RunConsole.removeConsole(rc2);
- ((DockerConnection) connection)
- .removeContainer(containerId);
+ // Wait for the container to finish
+ final IDockerContainerExit status = ((DockerConnection) connection)
+ .waitForContainer(containerId);
+ Display.getDefault().syncExec(() -> {
+ rc.setTitle(
+ Messages.getFormattedString(LAUNCH_EXITED_TITLE,
+ new String[] {
+ status.statusCode().toString(),
+ cmdList.get(0), imageName }));
+ rc.showConsole();
+ // We used a TM Terminal to receive the output of the
+ // session and
+ // then sent the output to the RunConsole. Remove the
+ // terminal
+ // tab that got created now that we are finished and all
+ // data is shown
+ // in Console View.
+ IWorkbenchPage page = PlatformUI.getWorkbench()
+ .getActiveWorkbenchWindow().getActivePage();
+ IViewPart terminalView = page.findView(
+ "org.eclipse.tm.terminal.view.ui.TerminalsView");
+ CTabFolder ctabfolder = terminalView
+ .getAdapter(CTabFolder.class);
+ if (ctabfolder != null) {
+ CTabItem[] items = ctabfolder.getItems();
+ for (CTabItem item : items) {
+ if (item.getText().endsWith(info.name())) {
+ item.dispose();
+ break;
+ }
+ }
+ }
+ });
+ // Let any container listener know that the container is
+ // finished
+ if (containerListener != null)
+ containerListener.done();
+
+ if (!keepContainer) {
+ ((DockerConnection) connection)
+ .removeContainer(containerId);
+ }
+ } else {
+ OutputStream stream = null;
+ RunConsole oldConsole = getConsole();
+ final RunConsole rc = RunConsole.findConsole(containerId,
+ consoleId);
+ setConsole(rc);
+ rc.clearConsole();
+ if (oldConsole != null)
+ RunConsole.removeConsole(oldConsole);
+ Display.getDefault().syncExec(() -> rc.setTitle(Messages
+ .getFormattedString(LAUNCH_TITLE, new String[] {
+ cmdList.get(0), imageName })));
+ // if (!rc.isAttached()) {
+ rc.attachToConsole(connection, containerId);
+ // }
+ if (rc != null) {
+ stream = rc.getOutputStream();
+ if (containerListener != null) {
+ ((ConsoleOutputStream) stream)
+ .addConsoleListener(containerListener);
+ }
+ }
+ // Create a unique logging thread id which has container id
+ // and console id
+ String loggingId = containerId + "." + consoleId;
+ ((DockerConnection) connection).startContainer(containerId,
+ loggingId, stream);
+ if (rc != null)
+ rc.showConsole();
+ if (containerListener != null) {
+ IDockerContainerInfo info = ((DockerConnection) connection)
+ .getContainerInfo(containerId);
+ containerListener.containerInfo(info);
+ }
+
+ // Wait for the container to finish
+ final IDockerContainerExit status = ((DockerConnection) connection)
+ .waitForContainer(containerId);
+ Display.getDefault().syncExec(() -> {
+ rc.setTitle(
+ Messages.getFormattedString(LAUNCH_EXITED_TITLE,
+ new String[] {
+ status.statusCode().toString(),
+ cmdList.get(0), imageName }));
+ rc.showConsole();
+ });
+
+ // Let any container listener know that the container is
+ // finished
+ if (containerListener != null)
+ containerListener.done();
+
+ if (!keepContainer) {
+ // Drain the logging thread before we remove the
+ // container (we need to use the logging id)
+ Thread.sleep(1000);
+ ((DockerConnection) connection)
+ .stopLoggingThread(loggingId);
+ // Look for any Display Log console that the user may
+ // have opened which would be
+ // separate and make sure it is removed as well
+ RunConsole rc2 = RunConsole
+ .findConsole(((DockerConnection) connection)
+ .getContainer(containerId));
+ if (rc2 != null)
+ RunConsole.removeConsole(rc2);
+ ((DockerConnection) connection)
+ .removeContainer(containerId);
+ }
}
} catch (final DockerException e2) {
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 d1e0f3a..d1fcdc2 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
@@ -268,7 +268,7 @@
&& connection.getContainerInfo(container.id()) != null
&& connection.getContainerInfo(container.id()).config() != null
&& connection.getContainerInfo(container.id()).config().tty()) {
- RunConsole.attachToTerminal(connection, container.id());
+ RunConsole.attachToTerminal(connection, container.id(), null);
return null;
}
final boolean autoLogOnStart = Activator.getDefault().getPreferenceStore()
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 0192e32..a8f9b24 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
@@ -49,7 +49,7 @@
final String name = container.name();
if (connection.getContainerInfo(id).config().tty()) {
- RunConsole.attachToTerminal(connection, id);
+ RunConsole.attachToTerminal(connection, id, null);
return null;
}
try {
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/consoles/RunConsole.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/consoles/RunConsole.java
index 4a24048..116acaa 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/consoles/RunConsole.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/consoles/RunConsole.java
@@ -19,6 +19,7 @@
import org.eclipse.linuxtools.docker.core.IDockerContainer;
import org.eclipse.linuxtools.docker.core.IDockerContainerState;
import org.eclipse.linuxtools.internal.docker.core.DockerConnection;
+import org.eclipse.linuxtools.internal.docker.core.DockerConsoleOutputStream;
import org.eclipse.linuxtools.internal.docker.ui.views.DVMessages;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
@@ -142,7 +143,6 @@
*/
public void attachToConsole(final IDockerConnection connection) {
final InputStream in = getInputStream();
- final OutputStream out = newOutputStream();
Thread t = new Thread(() -> {
try {
DockerConnection conn = (DockerConnection) connection;
@@ -155,7 +155,7 @@
}
state = conn.getContainerInfo(containerId).state();
} while (!state.running() && state.finishDate() == null);
- conn.attachCommand(containerId, in, out);
+ conn.attachCommand(containerId, in, null);
}
} catch (Exception e) {
}
@@ -164,7 +164,8 @@
attached = true;
}
- public static void attachToTerminal (final IDockerConnection connection, final String containerId) {
+ public static void attachToTerminal(final IDockerConnection connection,
+ final String containerId, final DockerConsoleOutputStream out) {
Thread t = new Thread(() -> {
try {
DockerConnection conn = (DockerConnection) connection;
@@ -176,7 +177,7 @@
}
state = conn.getContainerInfo(containerId).state();
} while (!state.running() && state.finishDate() == null);
- conn.attachCommand(containerId, null, null);
+ conn.attachCommand(containerId, null, out);
} catch (Exception e) {
}
});
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/ContainerCommandProcess.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/ContainerCommandProcess.java
index 4797187..f58778e 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/ContainerCommandProcess.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/launch/ContainerCommandProcess.java
@@ -65,14 +65,32 @@
this.keepContainer = keepContainer;
// Lambda Runnable
Runnable logContainer = () -> {
+ PipedOutputStream pipedOut = null;
+ PipedOutputStream pipedErr = null;
try (PipedOutputStream pipedStdout = new PipedOutputStream(stdout);
PipedOutputStream pipedStderr = new PipedOutputStream(
stderr)) {
+ pipedOut = pipedStdout;
+ pipedErr = pipedStderr;
connection.attachLog(containerId, pipedStdout, pipedStderr);
pipedStdout.flush();
pipedStderr.flush();
} catch (DockerException | InterruptedException | IOException e) {
- // do nothing but close output streams
+ // do nothing but flush/close output streams
+ if (pipedOut != null) {
+ try {
+ pipedOut.flush();
+ } catch (IOException e1) {
+ // ignore
+ }
+ }
+ if (pipedErr != null) {
+ try {
+ pipedErr.flush();
+ } catch (IOException e1) {
+ // ignore
+ }
+ }
}
};
@@ -93,12 +111,19 @@
} catch (InterruptedException e1) {
// ignore
}
+ thread.interrupt();
+ while (thread.isAlive()) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
this.stdout.close();
this.stderr.close();
} catch (IOException e) {
// ignore
}
- thread.interrupt();
}
@Override
@@ -262,6 +287,14 @@
try {
IDockerContainerExit exit = connection
.waitForContainer(containerId);
+ thread.interrupt();
+ while (thread.isAlive()) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
connection.stopLoggingThread(containerId);
if (!keepContainer) {
connection.removeContainer(containerId);