/******************************************************************************* * Copyright (c) 2004, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Mike Morearty - Bug 255310: Launching only gets the progress bar to 91% *******************************************************************************/ package org.eclipse.debug.core.model; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IBreakpointManager; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.IStatusHandler; import org.eclipse.debug.internal.core.DebugCoreMessages; import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; import com.ibm.icu.text.MessageFormat; /** * Default implementation of a launch configuration delegate. Provides * convenience methods for computing the build order of projects, * building projects, and searching for errors in the workspace. The * default pre-launch check prompts the user to launch in debug mode * if breakpoints are present in the workspace. *
* Clients implementing launch configuration delegates should subclass * this class. *
* @since 3.0 */ public abstract class LaunchConfigurationDelegate implements ILaunchConfigurationDelegate2 { /** * Constant to define debug.core for the status codes * * @since 3.2 */ private static final String DEBUG_CORE = "org.eclipse.debug.core"; //$NON-NLS-1$ /** * Constant to define debug.ui for the status codes * * @since 3.2 */ private static final String DEBUG_UI = "org.eclipse.debug.ui"; //$NON-NLS-1$ /** * Status code for which a UI prompter is registered. */ protected static final IStatus promptStatus = new Status(IStatus.INFO, DEBUG_UI, 200, IInternalDebugCoreConstants.EMPTY_STRING, null); /** * Status code for which a prompter is registered to ask the user if they * want to launch in debug mode when breakpoints are present. */ protected static final IStatus switchToDebugPromptStatus = new Status(IStatus.INFO, DEBUG_CORE, 201, IInternalDebugCoreConstants.EMPTY_STRING, null); /** * Status code for which a prompter is registered to ask the user if the * want to continue launch despite existing compile errors */ protected static final IStatus complileErrorPromptStatus = new Status(IStatus.INFO, DEBUG_CORE, 202, IInternalDebugCoreConstants.EMPTY_STRING, null); /** * Status code for which a prompter will ask the user to save any/all of the dirty editors which have only to do * with this launch (scoping them to the current launch/build) * * @since 3.2 */ protected static final IStatus saveScopedDirtyEditors = new Status(IStatus.INFO, DEBUG_CORE, 222, IInternalDebugCoreConstants.EMPTY_STRING, null); /** * Status code for which a prompter is registered to ask the user if the * want to continue launch despite existing compile errors in specific * projects. This enhances the 'compileErrorPromptStatus' by specifying * which projects the errors exist in. * * @since 3.1 */ protected static final IStatus complileErrorProjectPromptStatus = new Status(IStatus.INFO, DEBUG_CORE, 203, IInternalDebugCoreConstants.EMPTY_STRING, null); @Override public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException { return null; } @Override public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException { if (monitor != null) { monitor.beginTask("", 1); //$NON-NLS-1$ } try { IProject[] projects = getBuildOrder(configuration, mode); if (projects == null) { return true; } buildProjects(projects, new SubProgressMonitor(monitor, 1)); return false; } finally { if (monitor != null) { monitor.done(); } } } /** * Returns the projects to build before launching the given launch configuration * ornull
if the entire workspace should be built incrementally.
* Subclasses should override as required.
*
* @param configuration the configuration being launched
* @param mode launch mode
* @return projects to build, in build order, or null
* @throws CoreException if an exception occurs
*/
protected IProject[] getBuildOrder(ILaunchConfiguration configuration, String mode) throws CoreException {
return null;
}
/**
* Returns the set of projects to use when searching for errors or null
* if no search is to be done.
*
* @param configuration the configuration being launched
* @param mode launch mode
* @return a list of projects or null
* @throws CoreException if an exception occurs
*/
protected IProject[] getProjectsForProblemSearch(ILaunchConfiguration configuration, String mode) throws CoreException {
return null;
}
@Override
public boolean finalLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException {
monitor.beginTask("", 1); //$NON-NLS-1$
try {
IProject[] projects = getProjectsForProblemSearch(configuration, mode);
if (projects == null) {
return true; //continue launch
}
boolean continueLaunch = true;
monitor.subTask(DebugCoreMessages.LaunchConfigurationDelegate_6);
List* Since 3.2, this check also performs saving of resources before launching. *
* * @see org.eclipse.debug.core.model.ILaunchConfigurationDelegate2#preLaunchCheck(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.core.runtime.IProgressMonitor) */ @Override public boolean preLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException { if (!saveBeforeLaunch(configuration, mode, monitor)) { return false; } if (mode.equals(ILaunchManager.RUN_MODE) && configuration.supportsMode(ILaunchManager.DEBUG_MODE)) { IBreakpoint[] breakpoints= getBreakpoints(configuration); if (breakpoints == null) { return true; } for (int i = 0; i < breakpoints.length; i++) { if (breakpoints[i].isEnabled()) { IStatusHandler prompter = DebugPlugin.getDefault().getStatusHandler(promptStatus); if (prompter != null) { boolean launchInDebugModeInstead = ((Boolean)prompter.handleStatus(switchToDebugPromptStatus, configuration)).booleanValue(); if (launchInDebugModeInstead) { return false; //kill this launch } } // if no user prompt, or user says to continue (no need to check other breakpoints) return true; } } } // no enabled breakpoints... continue launch return true; } /** * Performs the scoped saving of resources before launching and returns whether * the launch should continue. By default, only resources contained within the projects * which are part of the build scope are considered. ** Subclasses may override this method if required. *
* * @param configuration the configuration being launched * @param mode the launch mode * @param monitor progress monitor * @return whether the launch should continue * @throws CoreException if an exception occurs during the save * @since 3.2 */ protected boolean saveBeforeLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException { monitor.beginTask("", 1); //$NON-NLS-1$ try { IStatusHandler prompter = DebugPlugin.getDefault().getStatusHandler(promptStatus); if(prompter != null) { //do save here and remove saving from DebugUIPlugin to avoid it 'trumping' this save IProject[] buildOrder = getBuildOrder(configuration, mode); if(!((Boolean)prompter.handleStatus(saveScopedDirtyEditors, new Object[]{configuration, buildOrder})).booleanValue()) { return false; } } return true; } finally { monitor.done(); } } /** * Returns the breakpoint collection that is relevant for this launch delegate. * By default this is all the breakpoints registered with the Debug breakpoint manager. * * @param configuration the configuration to get associated breakpoints for * @since 3.1 * @return the breakpoints that are relevant for this launch delegate */ protected IBreakpoint[] getBreakpoints(ILaunchConfiguration configuration) { IBreakpointManager breakpointManager = DebugPlugin.getDefault().getBreakpointManager(); if (!breakpointManager.isEnabled()) { // no need to check breakpoints individually. return null; } return breakpointManager.getBreakpoints(); } /** * Returns an array of projects in their suggested build order * containing all of the projects specified bybaseProjects
* and all of their referenced projects.
*
* @param baseProjects a collection of projects
* @return an array of projects in their suggested build order
* containing all of the projects specified by baseProjects
* @throws CoreException if an error occurs while computing referenced
* projects
*/
protected IProject[] computeReferencedBuildOrder(IProject[] baseProjects) throws CoreException {
HashSetproject
to the given
* set.
*
* @param project project
* @param references set to which referenced projects are added
* @throws CoreException if an error occurs while computing referenced
* projects
*/
protected void addReferencedProjects(IProject project, Setprojects
sorted
* according to their build order.
*/
protected IProject[] computeBuildOrder(IProject[] projects) {
String[] orderedNames = ResourcesPlugin.getWorkspace().getDescription().getBuildOrder();
if (orderedNames != null) {
List