Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Duft2016-11-25 13:41:41 +0000
committerSarika Sinha2017-01-13 03:30:26 +0000
commit1c1d17b82a223fb8fcc69b4883a71b8744899ccb (patch)
treec202e984d42407b607ac29cf95168bd6c04ffc29
parentfb136251cd02ed0b4812d1c65923b3abe79a1d40 (diff)
downloadeclipse.platform.debug-1c1d17b82a223fb8fcc69b4883a71b8744899ccb.tar.gz
eclipse.platform.debug-1c1d17b82a223fb8fcc69b4883a71b8744899ccb.tar.xz
eclipse.platform.debug-1c1d17b82a223fb8fcc69b4883a71b8744899ccb.zip
Launch Groups: Support to wait for output on child stdout
This adds support to listen for output on the console of the launched item before continuing the launch. Bug: 508420 Change-Id: I84027592c82b546ddf60c415bcc7047d9bc5490a Signed-off-by: Markus Duft <markus.duft@ssi-schaefer.com>
-rw-r--r--org.eclipse.debug.core/META-INF/MANIFEST.MF1
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java7
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties3
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunch.java3
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunchConfigurationDelegate.java45
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunchElement.java3
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/observer/ProcessObserver.java54
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/observer/StreamObserver.java73
-rw-r--r--org.eclipse.debug.tests/src/org/eclipse/debug/tests/launching/LaunchGroupTests.java189
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.java3
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.properties3
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/groups/GroupLaunchConfigurationSelectionDialog.java53
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/groups/GroupLaunchConfigurationTabGroup.java21
13 files changed, 407 insertions, 51 deletions
diff --git a/org.eclipse.debug.core/META-INF/MANIFEST.MF b/org.eclipse.debug.core/META-INF/MANIFEST.MF
index e306ac17c..5e1017435 100644
--- a/org.eclipse.debug.core/META-INF/MANIFEST.MF
+++ b/org.eclipse.debug.core/META-INF/MANIFEST.MF
@@ -15,6 +15,7 @@ Export-Package: org.eclipse.debug.core,
org.eclipse.debug.internal.core;x-friends:="org.eclipse.debug.ui,org.eclipse.debug.tests,org.eclipse.debug.examples.mixedmode",
org.eclipse.debug.internal.core.commands;x-friends:="org.eclipse.debug.ui",
org.eclipse.debug.internal.core.groups,
+ org.eclipse.debug.internal.core.groups.observer;x-internal:=true,
org.eclipse.debug.internal.core.sourcelookup;x-friends:="org.eclipse.debug.ui",
org.eclipse.debug.internal.core.sourcelookup.containers;x-friends:="org.eclipse.debug.ui",
org.eclipse.debug.internal.core.variables;x-friends:="org.eclipse.debug.ui,org.eclipse.jdt.debug.ui"
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java
index 48bec126b..e3bb0ccc7 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java
@@ -32,20 +32,19 @@ public class DebugCoreMessages extends NLS {
public static String DebugPlugin_8;
public static String DebugPlugin_Eclipse_runtime_does_not_support_working_directory_2;
public static String EnvironmentVariableResolver_0;
+ public static String GroupLaunchConfigurationDelegate_waiting;
+ public static String GroupLaunchConfigurationDelegate_failedWait;
public static String GroupLaunchConfigurationDelegate_Delay;
public static String GroupLaunchConfigurationDelegate_Delaying;
public static String GroupLaunchConfigurationDelegate_Launching;
public static String GroupLaunchConfigurationDelegate_mode_debug;
-
public static String GroupLaunchConfigurationDelegate_mode_inherit;
-
public static String GroupLaunchConfigurationDelegate_mode_profile;
-
public static String GroupLaunchConfigurationDelegate_mode_run;
-
public static String GroupLaunchConfigurationDelegate_None;
public static String GroupLaunchConfigurationDelegate_Wait_until_terminated;
public static String GroupLaunchConfigurationDelegate_Waiting_for_termination;
+ public static String GroupLaunchElement_outputRegexp;
public static String LaunchConfiguration_0;
public static String LaunchConfiguration_11;
public static String LaunchConfiguration_13;
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties
index 0e20ad951..eb9e35f51 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties
@@ -26,6 +26,8 @@ DebugPlugin_6=An exception occurred in asynchronous runnable.
DebugPlugin_7=An exception occurred while filtering debug events.
DebugPlugin_8=An exception occurred while dispatching debug events.
EnvironmentVariableResolver_0=Environment variable not specified
+GroupLaunchConfigurationDelegate_waiting=Waiting for ''{0}'' on the console of ''{1}''.
+GroupLaunchConfigurationDelegate_failedWait=Failed to await output ''{0}'' on the console of ''{1}''.
GroupLaunchConfigurationDelegate_Delay=Delay
GroupLaunchConfigurationDelegate_Delaying=Delaying next launch by {0} seconds
GroupLaunchConfigurationDelegate_Launching=Launching ''{0}''
@@ -36,6 +38,7 @@ GroupLaunchConfigurationDelegate_mode_run=run
GroupLaunchConfigurationDelegate_None=None
GroupLaunchConfigurationDelegate_Wait_until_terminated=Wait until terminated
GroupLaunchConfigurationDelegate_Waiting_for_termination=Waiting for termination of ''{0}''
+GroupLaunchElement_outputRegexp=Wait for console output (regexp)
SystemPropertyResolver_0=System property not specified
InputStreamMonitor_label=Input Stream Monitor
Launch_terminate_failed=Terminate failed
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunch.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunch.java
index 2c1b519c6..e611a4686 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunch.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunch.java
@@ -91,7 +91,8 @@ public class GroupLaunch extends Launch implements ILaunchesListener2 {
}
if (subLaunches.size() == 0) {
- return false;
+ return fLaunched; // in case we're done launching and there is
+ // nobody -> terminated
}
for (ILaunch launch : subLaunches.keySet()) {
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunchConfigurationDelegate.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunchConfigurationDelegate.java
index fccd5f8c3..69885d7cd 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunchConfigurationDelegate.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunchConfigurationDelegate.java
@@ -19,6 +19,10 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
@@ -33,10 +37,13 @@ import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.IStatusHandler;
import org.eclipse.debug.core.model.ILaunchConfigurationDelegate2;
+import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
import org.eclipse.debug.internal.core.DebugCoreMessages;
import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
import org.eclipse.debug.internal.core.groups.GroupLaunchElement.GroupElementPostLaunchAction;
+import org.eclipse.debug.internal.core.groups.observer.ProcessObserver;
+import org.eclipse.debug.internal.core.groups.observer.StreamObserver;
import org.eclipse.osgi.util.NLS;
/**
@@ -193,11 +200,46 @@ public class GroupLaunchConfigurationDelegate extends LaunchConfigurationDelegat
}
break;
+ case OUTPUT_REGEXP:
+ String regexp = (String) le.actionParam;
+ if (regexp != null) {
+ monitor.subTask(NLS.bind(DebugCoreMessages.GroupLaunchConfigurationDelegate_waiting, regexp, subLaunch.getLaunchConfiguration().getName()));
+ if (!waitForOutputMatching(subLaunch, monitor, regexp)) {
+ throw new RuntimeException(NLS.bind(DebugCoreMessages.GroupLaunchConfigurationDelegate_failedWait, regexp, le.name));
+ }
+ }
+
+ break;
+
default:
assert false : "new post launch action type is missing logic"; //$NON-NLS-1$
}
}
+ // blocks until a specific string is in the log output
+ private boolean waitForOutputMatching(ILaunch launch, IProgressMonitor m, String regexp) {
+ int processCount = launch.getProcesses().length;
+ final ExecutorService executor = Executors.newCachedThreadPool();
+ final CountDownLatch countDownLatch = new CountDownLatch(processCount);
+ Future<Integer> process = null;
+ for (IProcess p : launch.getProcesses()) {
+ process = executor.submit(new ProcessObserver(m, p, countDownLatch));
+ executor.submit(new StreamObserver(m, p, regexp, countDownLatch));
+ }
+ try {
+ countDownLatch.await();
+ } catch (InterruptedException e) {
+ // should not happen at all!
+ }
+ executor.shutdown();
+ // process terminated before condition
+ if (process == null || process.isDone()) {
+ return false;
+ }
+ // condition matched
+ return true;
+ }
+
/*
* (non-Javadoc)
* @see
@@ -293,6 +335,9 @@ public class GroupLaunchConfigurationDelegate extends LaunchConfigurationDelegat
DebugPlugin.log(exc);
}
}
+ if (action == GroupElementPostLaunchAction.OUTPUT_REGEXP) {
+ actionParam = attrs.get(getProp(index, ACTION_PARAM_PROP));
+ }
el.action = action;
el.actionParam = actionParam;
if (attrs.containsKey(getProp(index, ADOPT_PROP))) {
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunchElement.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunchElement.java
index 767f90514..5a409b8c8 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunchElement.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/GroupLaunchElement.java
@@ -34,7 +34,8 @@ public class GroupLaunchElement {
public static enum GroupElementPostLaunchAction {
NONE(DebugCoreMessages.GroupLaunchConfigurationDelegate_None), //
WAIT_FOR_TERMINATION(DebugCoreMessages.GroupLaunchConfigurationDelegate_Wait_until_terminated), //
- DELAY(DebugCoreMessages.GroupLaunchConfigurationDelegate_Delay);
+ DELAY(DebugCoreMessages.GroupLaunchConfigurationDelegate_Delay), //
+ OUTPUT_REGEXP(DebugCoreMessages.GroupLaunchElement_outputRegexp);
private final String description;
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/observer/ProcessObserver.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/observer/ProcessObserver.java
new file mode 100644
index 000000000..7261d9234
--- /dev/null
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/observer/ProcessObserver.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2016 SSI Schaefer and others.
+ * 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:
+ * SSI Schaefer
+ *******************************************************************************/
+package org.eclipse.debug.internal.core.groups.observer;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.model.IProcess;
+
+/**
+ * The {@code ProcessObserver} observes a given {@linkplain IProcess process} instance and notifies
+ * a {@linkplain CountDownLatch synchronization object} when the process terminates.
+ */
+public final class ProcessObserver implements Callable<Integer> {
+ private final IProcess p;
+ private final IProgressMonitor pMonitor;
+ private final CountDownLatch countDownLatch;
+
+ public ProcessObserver(IProgressMonitor monitor, IProcess p, CountDownLatch countDownLatch) {
+ this.p = p;
+ this.pMonitor = monitor;
+ this.countDownLatch = countDownLatch;
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ try {
+ while (!p.isTerminated() && !pMonitor.isCanceled()) {
+ TimeUnit.MILLISECONDS.sleep(250);
+
+ if (countDownLatch.getCount() == 0) {
+ break;
+ }
+ }
+ // check if terminated or timeout
+ if (p.isTerminated()) {
+ return p.getExitValue();
+ }
+ return 0;
+ } finally {
+ countDownLatch.countDown();
+ }
+ }
+}
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/observer/StreamObserver.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/observer/StreamObserver.java
new file mode 100644
index 000000000..437382149
--- /dev/null
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/groups/observer/StreamObserver.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2016 SSI Schaefer and others.
+ * 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:
+ * SSI Schaefer
+ *******************************************************************************/
+package org.eclipse.debug.internal.core.groups.observer;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.IStreamListener;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.IStreamMonitor;
+import org.eclipse.debug.core.model.IStreamsProxy;
+
+/**
+ * The {@code StreamObserver} observes a given {@linkplain IStreamsProxy output stream} instance and
+ * notifies a {@linkplain CountDownLatch synchronization object} when a given string appears in the
+ * output.
+ */
+public class StreamObserver implements Runnable {
+ private final String stringPattern;
+ private final IProcess process;
+ private final CountDownLatch countDownLatch;
+ private final IProgressMonitor pMonitor;
+
+ public StreamObserver(IProgressMonitor monitor, IProcess process, String pattern,
+ CountDownLatch countDownLatch) {
+ this.process = process;
+ this.pMonitor = monitor;
+ this.stringPattern = pattern;
+ this.countDownLatch = countDownLatch;
+ }
+
+ @Override
+ public void run() {
+ // append wild card if not provided
+ StringBuilder patternBuilder = new StringBuilder();
+ if (!stringPattern.startsWith(".*")) { //$NON-NLS-1$
+ patternBuilder.append(".*"); //$NON-NLS-1$
+ }
+ patternBuilder.append(stringPattern);
+ if (!stringPattern.endsWith(".*")) { //$NON-NLS-1$
+ patternBuilder.append(".*"); //$NON-NLS-1$
+ }
+ // create pattern and start listening to the output
+ final Pattern pattern = Pattern.compile(patternBuilder.toString(), Pattern.MULTILINE);
+ final IStreamMonitor outputStreamMonitor = process.getStreamsProxy()
+ .getOutputStreamMonitor();
+ outputStreamMonitor.addListener(new IStreamListener() {
+ @Override
+ public void streamAppended(String text, IStreamMonitor monitor) {
+ if (countDownLatch.getCount() == 0) {
+ outputStreamMonitor.removeListener(this);
+ return;
+ }
+
+ Matcher matcher = pattern.matcher(text);
+ if (!matcher.find() && !pMonitor.isCanceled()) {
+ return;
+ }
+ countDownLatch.countDown();
+ }
+ });
+ }
+}
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/launching/LaunchGroupTests.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/launching/LaunchGroupTests.java
index b046728c6..b2bb6ce27 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/launching/LaunchGroupTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/launching/LaunchGroupTests.java
@@ -3,7 +3,11 @@ package org.eclipse.debug.tests.launching;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.core.runtime.CoreException;
@@ -13,8 +17,11 @@ import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchListener;
import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.IStreamListener;
import org.eclipse.debug.core.model.IDisconnect;
import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.IStreamMonitor;
+import org.eclipse.debug.core.model.IStreamsProxy;
import org.eclipse.debug.internal.core.groups.GroupLaunchConfigurationDelegate;
import org.eclipse.debug.internal.core.groups.GroupLaunchElement;
import org.eclipse.debug.internal.core.groups.GroupLaunchElement.GroupElementPostLaunchAction;
@@ -149,23 +156,7 @@ public class LaunchGroupTests extends AbstractLaunchTest {
if (l.getLaunchConfiguration().contentsEqual(t1)) {
// add a dummy process, otherwise the launch never
// terminates...
- InvocationHandler handler = new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- String name = method.getName();
- if (name.equals("equals")) { //$NON-NLS-1$
- return args.length == 1 && proxy == args[0];
- }
- if (name.equals("getStreamsProxy")) { //$NON-NLS-1$
- return null;
- }
- return Boolean.TRUE;
- }
- };
- IProcess process = (IProcess) Proxy.newProxyInstance(LaunchGroupTests.class.getClassLoader(), new Class[] {
- IProcess.class,
- IDisconnect.class }, handler);
- l.addProcess(process);
+ attachDummyProcess(l);
l.terminate();
}
}
@@ -174,6 +165,7 @@ public class LaunchGroupTests extends AbstractLaunchTest {
e.printStackTrace();
}
}
+
}.start();
// attention: need to do this before launching!
@@ -192,6 +184,7 @@ public class LaunchGroupTests extends AbstractLaunchTest {
assertTrue("history[2] should be Test1", history[2].contentsEqual(t1)); //$NON-NLS-1$
}
+
public void testAdopt() throws Exception {
final ILaunchConfiguration t1 = getLaunchConfiguration("Test1"); //$NON-NLS-1$
final ILaunchConfiguration grp = createLaunchGroup(DEF_GRP_NAME, createLaunchGroupElement(t1, GroupElementPostLaunchAction.NONE, null, false), createLaunchGroupElement(t1, GroupElementPostLaunchAction.NONE, null, true));
@@ -237,4 +230,166 @@ public class LaunchGroupTests extends AbstractLaunchTest {
assertTrue("Test1 should be launched only once", launchCount.get() == 1); //$NON-NLS-1$
}
+ public void testWaitForOutput() throws Exception {
+ String testOutput = "TestOutput"; //$NON-NLS-1$
+
+ final ILaunchConfiguration t1 = getLaunchConfiguration("Test1"); //$NON-NLS-1$
+ ILaunchConfiguration t2 = getLaunchConfiguration("Test2"); //$NON-NLS-1$
+ ILaunchConfiguration grp = createLaunchGroup(DEF_GRP_NAME, createLaunchGroupElement(t1, GroupElementPostLaunchAction.OUTPUT_REGEXP, testOutput, false), createLaunchGroupElement(t2, GroupElementPostLaunchAction.NONE, null, false));
+
+ // attach a dummy process to the launch once it is launched.
+ final DummyAttachListener attachListener = new DummyAttachListener(t1);
+ getLaunchManager().addLaunchListener(attachListener);
+
+ // start a thread that will produce output on the dummy process after
+ // some time
+ new Thread("Output Producer") { //$NON-NLS-1$
+ @Override
+ public void run() {
+ try {
+ // wait some time before causing the group to continue
+ Thread.sleep(2000);
+ attachListener.getStream().write("TestOutput"); //$NON-NLS-1$
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+
+ long start = System.currentTimeMillis();
+
+ // attention: need to do this before launching!
+ LaunchHistory runHistory = getRunLaunchHistory();
+
+ // launching the group should block until the output is produced
+ grp.launch(ILaunchManager.RUN_MODE, new NullProgressMonitor());
+ getLaunchManager().removeLaunchListener(attachListener);
+
+ assertTrue("output was not awaited", (System.currentTimeMillis() - start) > 2000); //$NON-NLS-1$
+
+ ILaunchConfiguration[] history = runHistory.getHistory();
+ assertTrue("history should be size 3", history.length == 3); //$NON-NLS-1$
+ assertTrue("history[0] should be Test Group", history[0].contentsEqual(grp)); //$NON-NLS-1$
+ assertTrue("history[1] should be Test2", history[1].contentsEqual(t2)); //$NON-NLS-1$
+ assertTrue("history[2] should be Test1", history[2].contentsEqual(t1)); //$NON-NLS-1$
+ }
+
+ protected Set<ILaunch> findRunningLaunch(ILaunchConfiguration cfg) {
+ Set<ILaunch> result = new HashSet<>();
+ for (ILaunch l : getLaunchManager().getLaunches()) {
+ if (l.isTerminated()) {
+ continue;
+ }
+ if (l.getLaunchConfiguration().equals(cfg)) {
+ result.add(l);
+ }
+ }
+ return result;
+ }
+
+ private static DummyStream attachDummyProcess(final ILaunch l) {
+ final DummyStream dummy = new DummyStream();
+ final InvocationHandler streamProxyHandler = new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ String name = method.getName();
+ if (name.equals("getOutputStreamMonitor")) { //$NON-NLS-1$
+ return dummy;
+ }
+ return null;
+ }
+ };
+
+ final InvocationHandler handler = new InvocationHandler() {
+ boolean terminated = false;
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ String name = method.getName();
+ if (name.equals("equals")) { //$NON-NLS-1$
+ return args.length == 1 && proxy == args[0];
+ }
+ if (name.equals("getStreamsProxy")) { //$NON-NLS-1$
+ return Proxy.newProxyInstance(LaunchGroupTests.class.getClassLoader(), new Class[] {
+ IStreamsProxy.class }, streamProxyHandler);
+ }
+ if (name.equals("getLaunch")) { //$NON-NLS-1$
+ return l;
+ }
+ if (name.equals("getLabel")) { //$NON-NLS-1$
+ return l.getLaunchConfiguration().getName();
+ }
+ if (name.equals("getAttribute")) { //$NON-NLS-1$
+ return null;
+ }
+ if (name.equals("isTerminated")) { //$NON-NLS-1$
+ return terminated;
+ }
+ if (name.equals("terminate")) { //$NON-NLS-1$
+ terminated = true;
+ }
+ return Boolean.TRUE;
+ }
+ };
+ IProcess process = (IProcess) Proxy.newProxyInstance(LaunchGroupTests.class.getClassLoader(), new Class[] {
+ IProcess.class, IDisconnect.class }, handler);
+ l.addProcess(process);
+ return dummy;
+ }
+
+ private static final class DummyStream implements IStreamMonitor {
+
+ private final List<IStreamListener> listeners = new ArrayList<>();
+
+ @Override
+ public void addListener(IStreamListener listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public String getContents() {
+ return null;
+ }
+
+ @Override
+ public void removeListener(IStreamListener listener) {
+ listeners.remove(listener);
+ }
+
+ public void write(String s) {
+ for (IStreamListener l : listeners) {
+ l.streamAppended(s, null);
+ }
+ }
+
+ }
+
+ private static final class DummyAttachListener implements ILaunchListener {
+
+ private ILaunchConfiguration cfg;
+ private DummyStream stream;
+
+ public DummyAttachListener(ILaunchConfiguration cfg) {
+ this.cfg = cfg;
+ }
+
+ public DummyStream getStream() {
+ return stream;
+ }
+
+ @Override
+ public void launchRemoved(ILaunch launch) {
+ }
+
+ @Override
+ public void launchAdded(ILaunch launch) {
+ if (launch.getLaunchConfiguration().equals(cfg))
+ stream = attachDummyProcess(launch);
+ }
+
+ @Override
+ public void launchChanged(ILaunch launch) {
+ }
+
+ }
+
}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.java
index 49e6ab536..4cb94c20b 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.java
@@ -257,6 +257,9 @@ public class DebugUIMessages extends NLS {
public static String GroupLaunchConfigurationSelectionDialog_9;
public static String GroupLaunchConfigurationSelectionDialog_adoptText;
public static String GroupLaunchConfigurationSelectionDialog_adoptTooltip;
+ public static String GroupLaunchConfigurationSelectionDialog_errorNoRegexp;
+ public static String GroupLaunchConfigurationSelectionDialog_regexp;
+ public static String GroupLaunchConfigurationTabGroup_0;
public static String GroupLaunchConfigurationTabGroup_1;
public static String GroupLaunchConfigurationTabGroup_10;
public static String GroupLaunchConfigurationTabGroup_12;
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.properties b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.properties
index 912758da5..e082ca5a5 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.properties
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugUIMessages.properties
@@ -130,6 +130,9 @@ GroupLaunchConfigurationSelectionDialog_14=Add one or more launch configurations
GroupLaunchConfigurationSelectionDialog_15=Edit an existing entry in the launch group
GroupLaunchConfigurationSelectionDialog_adoptText=Adopt launch if already running
GroupLaunchConfigurationSelectionDialog_adoptTooltip=Instead of launching a new process, adds the running launch to the group.
+GroupLaunchConfigurationSelectionDialog_errorNoRegexp=Enter a regular expression to wait for
+GroupLaunchConfigurationSelectionDialog_regexp=Regular Expression:
+GroupLaunchConfigurationTabGroup_0=Wait for output matching "{0}"
GroupLaunchConfigurationTabGroup_1=&Up
GroupLaunchConfigurationTabGroup_2=Do&wn
GroupLaunchConfigurationTabGroup_3=&Edit...
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/groups/GroupLaunchConfigurationSelectionDialog.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/groups/GroupLaunchConfigurationSelectionDialog.java
index 8ae809995..d79565184 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/groups/GroupLaunchConfigurationSelectionDialog.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/groups/GroupLaunchConfigurationSelectionDialog.java
@@ -39,6 +39,7 @@ import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.ILaunchGroup;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
@@ -81,8 +82,8 @@ class GroupLaunchConfigurationSelectionDialog extends TitleAreaDialog implements
private ViewerFilter emptyTypeFilter;
private IStructuredSelection fInitialSelection;
private ComboControlledStackComposite fStackComposite;
- private Label fDelayAmountLabel;
- private Text fDelayAmountWidget; // in seconds
+ private Label fActionParamLabel;
+ private Text fActionParamWidget; // in seconds
private boolean fForEditing; // true if dialog was opened to edit an entry,
// otherwise it was opened to add one
private ILaunchConfigurationType groupType;
@@ -236,6 +237,7 @@ class GroupLaunchConfigurationSelectionDialog extends TitleAreaDialog implements
combo.add(GroupElementPostLaunchAction.NONE.getDescription());
combo.add(GroupElementPostLaunchAction.WAIT_FOR_TERMINATION.getDescription());
combo.add(GroupElementPostLaunchAction.DELAY.getDescription());
+ combo.add(GroupElementPostLaunchAction.OUTPUT_REGEXP.getDescription());
combo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
@@ -247,36 +249,46 @@ class GroupLaunchConfigurationSelectionDialog extends TitleAreaDialog implements
});
combo.setText(action.getDescription());
- fDelayAmountLabel = new Label(comp, SWT.NONE);
- fDelayAmountLabel.setText(DebugUIMessages.GroupLaunchConfigurationSelectionDialog_9);
-
- fDelayAmountWidget = new Text(comp, SWT.SINGLE | SWT.BORDER);
- GridData gridData = new GridData();
- gridData.widthHint = convertWidthInCharsToPixels(8);
- fDelayAmountWidget.setLayoutData(gridData);
- fDelayAmountWidget.addModifyListener(new ModifyListener() {
+ fActionParamLabel = new Label(comp, SWT.NONE);
+ fActionParamWidget = new Text(comp, SWT.SINGLE | SWT.BORDER);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(fActionParamWidget);
+ fActionParamWidget.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
String text = ((Text) e.widget).getText();
- try {
- actionParam = Integer.valueOf(text);
- } catch (NumberFormatException exc) {
- actionParam = null;
+ if (action == GroupElementPostLaunchAction.DELAY) {
+ try {
+ actionParam = Integer.valueOf(text);
+ } catch (NumberFormatException exc) {
+ actionParam = null;
+ }
+ } else if (action == GroupElementPostLaunchAction.OUTPUT_REGEXP) {
+ actionParam = text;
}
validate();
}
});
if (actionParam instanceof Integer) {
- fDelayAmountWidget.setText(((Integer) actionParam).toString());
+ fActionParamWidget.setText(((Integer) actionParam).toString());
+ } else if (actionParam instanceof String) {
+ fActionParamWidget.setText(actionParam.toString());
}
showHideDelayAmountWidgets();
}
private void showHideDelayAmountWidgets() {
- final boolean visible = action == GroupElementPostLaunchAction.DELAY;
- fDelayAmountLabel.setVisible(visible);
- fDelayAmountWidget.setVisible(visible);
+ final boolean visible = (action == GroupElementPostLaunchAction.DELAY || action == GroupElementPostLaunchAction.OUTPUT_REGEXP);
+ fActionParamLabel.setVisible(visible);
+ fActionParamWidget.setVisible(visible);
+
+ if (action == GroupElementPostLaunchAction.DELAY) {
+ fActionParamLabel.setText(DebugUIMessages.GroupLaunchConfigurationSelectionDialog_9);
+ } else if (action == GroupElementPostLaunchAction.OUTPUT_REGEXP) {
+ fActionParamLabel.setText(DebugUIMessages.GroupLaunchConfigurationSelectionDialog_regexp);
+ }
+
+ fActionParamLabel.getParent().layout();
}
public ILaunchConfiguration[] getSelectedLaunchConfigurations() {
@@ -389,6 +401,11 @@ class GroupLaunchConfigurationSelectionDialog extends TitleAreaDialog implements
isValid = (actionParam instanceof Integer) && ((Integer) actionParam > 0);
setErrorMessage(isValid ? null : DebugUIMessages.GroupLaunchConfigurationSelectionDialog_10);
}
+
+ if (action == GroupElementPostLaunchAction.OUTPUT_REGEXP) {
+ isValid = actionParam instanceof String && !((String) actionParam).isEmpty();
+ setErrorMessage(isValid ? null : DebugUIMessages.GroupLaunchConfigurationSelectionDialog_errorNoRegexp);
+ }
}
if (ok_button != null) {
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/groups/GroupLaunchConfigurationTabGroup.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/groups/GroupLaunchConfigurationTabGroup.java
index 692c681a8..2dca579c2 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/groups/GroupLaunchConfigurationTabGroup.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/groups/GroupLaunchConfigurationTabGroup.java
@@ -155,17 +155,18 @@ public class GroupLaunchConfigurationTabGroup extends AbstractLaunchConfiguratio
if (columnIndex == 2) {
GroupElementPostLaunchAction action = el.action;
switch (action) {
- case NONE:
- return ""; //$NON-NLS-1$
- case WAIT_FOR_TERMINATION:
+ case NONE:
+ return ""; //$NON-NLS-1$
+ case WAIT_FOR_TERMINATION:
return action.getDescription();
- case DELAY:
- final Object actionParam = el.actionParam;
- return NLS.bind(DebugUIMessages.GroupLaunchConfigurationTabGroup_13,
- actionParam instanceof Integer ? Integer.toString((Integer) actionParam) : "?"); //$NON-NLS-1$
- default:
- assert false : "new post launch action missing logic here"; //$NON-NLS-1$
- return ""; //$NON-NLS-1$
+ case DELAY:
+ final Object actionParam = el.actionParam;
+ return NLS.bind(DebugUIMessages.GroupLaunchConfigurationTabGroup_13, actionParam instanceof Integer ? Integer.toString((Integer) actionParam) : "?"); //$NON-NLS-1$
+ case OUTPUT_REGEXP:
+ return NLS.bind(DebugUIMessages.GroupLaunchConfigurationTabGroup_0, el.actionParam);
+ default:
+ assert false : "new post launch action missing logic here"; //$NON-NLS-1$
+ return ""; //$NON-NLS-1$
}
}
return null;

Back to the top