Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Duft2016-11-25 08:41:41 -0500
committerSarika Sinha2017-01-12 22:30:26 -0500
commit1c1d17b82a223fb8fcc69b4883a71b8744899ccb (patch)
treec202e984d42407b607ac29cf95168bd6c04ffc29 /org.eclipse.debug.core
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>
Diffstat (limited to 'org.eclipse.debug.core')
-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
8 files changed, 183 insertions, 6 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();
+ }
+ });
+ }
+}

Back to the top