diff options
author | Jeff Johnston | 2017-08-22 00:01:10 +0000 |
---|---|---|
committer | Jeff Johnston | 2017-08-22 02:32:36 +0000 |
commit | 2519e6966422bf0ff346ad02c1abf196f95e9bea (patch) | |
tree | d66f5fd3d584f9a0f0b87598b8c3d7d5ae71b8fe | |
parent | ed0f26c313623f0b3dcf32c15bb9c2965e7ece8c (diff) | |
download | org.eclipse.linuxtools-2519e6966422bf0ff346ad02c1abf196f95e9bea.tar.gz org.eclipse.linuxtools-2519e6966422bf0ff346ad02c1abf196f95e9bea.tar.xz org.eclipse.linuxtools-2519e6966422bf0ff346ad02c1abf196f95e9bea.zip |
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>
(cherry picked from commit 659a766ff264ff53f8a72026fa753f39fc35f6f8)
Reviewed-on: https://git.eclipse.org/r/103420
8 files changed, 397 insertions, 79 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 4831fe9435..e8eaaae7eb 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.linuxtools.internal.docker.core.DockerImage.DockerImageQualif 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 @@ public class DockerConnection getContainers(force); } catch (DockerException e) { Activator.log(e); + return Collections.emptyList(); } } else if (!isContainersLoaded() || force) { @@ -984,6 +986,7 @@ public class DockerConnection latestImages = getImages(force); } catch (DockerException e) { Activator.log(e); + return Collections.emptyList(); } } else if (!isImagesLoaded() || force) { try { @@ -1933,7 +1936,6 @@ public class DockerConnection Activator.log(e); } } - } @Override @@ -2007,7 +2009,7 @@ public class DockerConnection } 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 @@ public class DockerConnection 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 @@ public class DockerConnection 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 @@ public class DockerConnection 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 @@ public class DockerConnection * 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 0000000000..e2c1d27f5d --- /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 0000000000..2b3cff95d4 --- /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 c5ea7e0fff..cc745da3fe 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.core.runtime.jobs.Job; 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.IDockerImageInfo; 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 @@ public class ContainerLauncher { } + // 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 @@ public class ContainerLauncher { .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 @@ public class ContainerLauncher { 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 (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(); + } + + // 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) { - ((ConsoleOutputStream) stream) - .addConsoleListener(containerListener); + out.addConsoleListener(new RunConsoleListenerBridge( + 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) { + ((DockerConnection) connection).startContainer(containerId, + null, null); IDockerContainerInfo info = ((DockerConnection) connection) .getContainerInfo(containerId); - containerListener.containerInfo(info); - } + if (containerListener != null) { + 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(); + // 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) - ((DockerConnection) connection) - .stopLoggingThread(loggingId); - while (((DockerConnection) connection).loggingStatus( - loggingId) == EnumDockerLoggingStatus.LOGGING_ACTIVE) { + // 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); } - // 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 d1e0f3a8cd..d1fcdc2a86 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 @@ public class CommandUtils { && 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 0192e328eb..a8f9b2450b 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 @@ public class DisplayContainerLogCommandHandler extends AbstractHandler { 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 4a240483c0..116acaabcc 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.IDockerConnection; 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 class RunConsole extends IOConsole { */ 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 @@ public class RunConsole extends IOConsole { } 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 @@ public class RunConsole extends IOConsole { 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 @@ public class RunConsole extends IOConsole { } 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 4797187576..f58778edb7 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 @@ public class ContainerCommandProcess extends Process { 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 @@ public class ContainerCommandProcess extends Process { } 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 @@ public class ContainerCommandProcess extends Process { 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); |