/*******************************************************************************
* Copyright (c) 2015, 2015 IBM Corporation 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:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.lang.ide.launching;
import static melnorme.utilbox.core.CoreUtil.array;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.Launch;
import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
import melnorme.lang.ide.core.EclipseCore;
import melnorme.lang.ide.core.LangCore;
import melnorme.lang.ide.core.launch.BuildTargetLaunchCreator;
import melnorme.lang.ide.core.launch.BuildTargetSource;
import melnorme.lang.ide.core.launch.CompositeBuildTargetSettings;
import melnorme.lang.ide.core.launch.LaunchMessages;
import melnorme.lang.ide.core.operations.build.BuildManager;
import melnorme.lang.ide.core.operations.build.BuildTarget;
import melnorme.lang.ide.core.utils.EclipseUtils;
import melnorme.lang.ide.core.utils.ProjectValidator;
import melnorme.lang.tooling.commands.CommandInvocation;
import melnorme.utilbox.collections.HashMap2;
import melnorme.utilbox.concurrency.OperationCancellation;
import melnorme.utilbox.core.CommonException;
import melnorme.utilbox.misc.Location;
public abstract class LangLaunchConfigurationDelegate extends LaunchConfigurationDelegate {
protected final BuildManager buildManager = LangCore.getBuildManager();
public LangLaunchConfigurationDelegate() {
super();
}
protected CoreException error(String message, Throwable exception) throws CoreException {
throw EclipseCore.createCoreException(message, exception);
}
protected CoreException errorMsg(String messagePattern, Object... arguments) throws CoreException {
throw error(MessageFormat.format(messagePattern, arguments), null);
}
/* ----------------- Launch ----------------- */
protected CompositeBuildTargetSettings buildTargetSettings;
protected EclipseProcessLauncher processLauncher;
protected BuildTarget buildTarget;
@Override
public final ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {
try {
buildTargetSettings = getBuildTargetSettings(configuration);
buildTarget = buildTargetSettings.getValidBuildTarget();
processLauncher = getValidLaunchInfo(configuration, buildTargetSettings);
} catch(CommonException ce) {
throw EclipseCore.createCoreException(ce);
}
if(ILaunchManager.RUN_MODE.equals(mode)) {
return getLaunchForRunMode(configuration, mode);
}
if(ILaunchManager.DEBUG_MODE.equals(mode)) {
return getLaunchForDebugMode(configuration, mode);
}
throw abort_UnsupportedMode(mode);
}
protected CoreException abort_UnsupportedMode(String mode) throws CoreException {
return errorMsg(LaunchMessages.LCD_errINTERNAL_UnsupportedMode, mode);
}
protected ILaunch getLaunchForRunMode(ILaunchConfiguration configuration, String mode) throws CoreException {
return new Launch(configuration, mode, null);
}
@SuppressWarnings("unused")
protected ILaunch getLaunchForDebugMode(ILaunchConfiguration configuration, String mode) throws CoreException {
throw abort_UnsupportedMode(mode);
}
protected CompositeBuildTargetSettings getBuildTargetSettings(ILaunchConfiguration configuration)
throws CoreException, CommonException {
BuildTargetLaunchCreator launchSettings = new BuildTargetLaunchCreator(configuration);
BuildTargetSource buildTargetSource = new BuildTargetSource() {
@Override
public ProjectValidator getProjectValidator() {
return new ProjectValidator();
};
@Override
public String getProjectName() {
return launchSettings.projectName;
}
@Override
public String getBuildTargetName() {
return launchSettings.getTargetName();
}
};
return new CompositeBuildTargetSettings(buildTargetSource) {
@Override
public String getExecutablePath() {
return launchSettings.getExecutablePath();
}
@Override
public CommandInvocation getBuildCommand() {
return launchSettings.getBuildCommand();
}
};
}
protected EclipseProcessLauncher getValidLaunchInfo(
ILaunchConfiguration configuration, CompositeBuildTargetSettings buildTargetSettings)
throws CommonException, CoreException {
IProject project = buildTargetSettings.getBuildTargetSupplier().getValidProject();
String workingDirectoryString = evaluateStringVars(
configuration.getAttribute(LaunchConstants.ATTR_WORKING_DIRECTORY, (String) null));
IPath workingDirectory = workingDirectoryString == null ?
project.getLocation() :
new Path(workingDirectoryString);
Location programLoc = buildTarget.getValidExecutableLocation(); // not null
String programArguments = configuration.getAttribute(LaunchConstants.ATTR_PROGRAM_ARGUMENTS, "");
String commandLine = programLoc.toString() + " " + programArguments;
Map<String, String> configEnv = configuration.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES,
new HashMap<>(0));
boolean appendEnv = configuration.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
CommandInvocation programInvocation = new CommandInvocation(commandLine, new HashMap2<>(configEnv), appendEnv);
return new EclipseProcessLauncher(
project,
programLoc,
workingDirectory,
programInvocation,
LaunchConstants.PROCESS_TYPE_ID
);
}
/* ----------------- Launch check ----------------- */
@Override
public final boolean preLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor)
throws CoreException {
if (monitor != null) {
monitor.subTask(LaunchMessages.LCD_PreparingLaunch);
}
doPreLaunchCheck(configuration, mode, monitor);
return super.preLaunchCheck(configuration, mode, monitor);
}
protected IStringVariableManager getVariableManager() {
return VariablesPlugin.getDefault().getStringVariableManager();
}
protected String evaluateStringVars(String expression) throws CoreException {
if(expression == null) {
return null;
}
return getVariableManager().performStringSubstitution(expression);
}
protected boolean doPreLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor)
throws CoreException {
return super.preLaunchCheck(configuration, mode, monitor);
}
@Override
protected IProject[] getProjectsForProblemSearch(ILaunchConfiguration configuration, String mode)
throws CoreException {
// XXX: This could perhaps be improved in the future
return array(processLauncher.project);
}
/* ----------------- Build ----------------- */
@Override
public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor)
throws CoreException {
try {
return doBuildForLaunch(configuration, mode, monitor);
} catch(CommonException e) {
throw EclipseCore.createCoreException(e);
} catch(OperationCancellation e) {
throw new OperationCanceledException();
}
}
protected boolean doBuildForLaunch(ILaunchConfiguration configuration, String mode,
IProgressMonitor pm) throws CoreException, CommonException, OperationCancellation {
IProject project = this.processLauncher.project;
if(buildTarget != null) {
buildManager.executeBuildTargetOperation(EclipseUtils.om(pm), project, buildTarget);
return false;
} else {
return super.buildForLaunch(configuration, mode, pm);
}
}
@Override
protected IProject[] getBuildOrder(ILaunchConfiguration configuration, String mode) throws CoreException {
return array(processLauncher.project);
}
/* ----------------- Actual launch ----------------- */
@Override
public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
throws CoreException {
SubMonitor subMonitor = SubMonitor.convert(monitor,
LaunchMessages.LCD_StartingLaunchConfiguration(configuration.getName()), 10);
try {
launchProcess(configuration, launch, subMonitor.split(10));
} catch (CommonException ce) {
throw EclipseCore.createCoreException(ce);
}
}
@SuppressWarnings("unused")
protected void launchProcess(ILaunchConfiguration configuration, ILaunch launch, IProgressMonitor monitor)
throws CoreException, CommonException {
processLauncher.launchProcess(launch);
}
}