package com.googlecode.grinderstone.debug.ui.launching;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.python.copiedfromeclipsesrc.JavaVmLocationFinder;
import org.python.pydev.core.IPythonPathNature;
import org.python.pydev.core.MisconfigurationException;
import org.python.pydev.core.REF;
import org.python.pydev.debug.core.Constants;
import org.python.pydev.debug.ui.launching.InvalidRunException;
import org.python.pydev.debug.ui.launching.PythonRunnerConfig;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.plugin.nature.PythonNature;
import org.python.pydev.ui.pythonpathconf.InterpreterInfo;
import com.googlecode.grinderstone.GrinderStonePlugin;
import com.googlecode.grinderstone.core.GrinderConstants;
import com.googlecode.grinderstone.debug.ui.launching.jdt.JavaProjectPyPathBuilder;
/**
* Class represents configuration for running/debugging grinder.
*
* @author Borislav Andruschuk
* @since GrinderStone 1.0
*/
public class GrinderRunnerConfig extends PythonRunnerConfig {
/** Holds run configuration. */
private ILaunchConfiguration configuration;
/** Mask run grinder as Jython run. */
public static final String RUN_GRINDER = RUN_JYTHON;
public GrinderRunnerConfig(ILaunchConfiguration conf, String mode) throws CoreException,
InvalidRunException, MisconfigurationException {
super(conf, mode, RUN_GRINDER);
configuration = conf;
}
public GrinderRunnerConfig(ILaunchConfiguration conf, String mode,
boolean makeArgumentsVariableSubstitution) throws CoreException,
InvalidRunException, MisconfigurationException {
super(conf, mode, RUN_GRINDER, makeArgumentsVariableSubstitution);
configuration = conf;
}
/**
* is GrinerStone is launching?
*
* @return <code>true</code> if GrinderStone is launching, otherwise <code>false</code>
*/
public boolean isGrinder() {
return true;
}
@Override
public String[] getCommandLine(boolean makeVariableSubstitution) throws CoreException {
List<String> cmdArgs = getCmdArgsForGrinder();
return cmdArgs == null ? new String[0] : cmdArgs.toArray(new String[cmdArgs.size()]);
}
/**
* Method returns command line parameters for grinder running/debugging
*
* @return list with command line parameters
* @throws CoreException threw if something wrong
*/
private List<String> getCmdArgsForGrinder() throws CoreException {
checkIfNotJython();
// TODO: program arguments not passed from Arguments tab
List<String> cmdArgs = new ArrayList<String>();
// "java.exe" -classpath "C:\bin\jython21\jython.jar" org.python.util.jython script %ARGS%
String java = JavaVmLocationFinder.findDefaultJavaExecutable().getAbsolutePath();
cmdArgs.add(java);
addGrinderAgentIfNecessary(cmdArgs);
cmdArgs.add("-classpath");
cmdArgs.add(generateClasspath());
cmdArgs.add("-Dpython.path=" + getPythonPath());
// TODO: add this parameters to UI configuration.
// cmdArgs.add("-Dpython.options.showJavaExceptions=true");
// cmdArgs.add("-Dpython.options.showPythonProxyExceptions=true");
// cmdArgs.add("-Dpython.verbose=debug");
if (isDebug) {
// cmdArgs.add("-Dpython.security.respectJavaAccessibility=false");
cmdArgs.add("-Dgrinder.debug.singleprocess.sharedclasses=net.grinder.*");
cmdArgs.add("-Dgrinder.debug.singleprocess=true");
cmdArgs.add("-Dgrinder.debug.singleprocess.runner="
+ GrinderConstants.WEAVER_ENTRY_POINT_CLASS);
cmdArgs.add("-Ddbg.script.folder=" + getPySrcAbsolutePath());
try {
cmdArgs.add("-Ddbg.script.parameter.port="
+ Integer.toString(getDebuggerListenConnector().getLocalPort()));
} catch (IOException e) {
throw new CoreException(PydevPlugin.makeStatus(IStatus.ERROR, "Unable to get port",
e));
}
}
cmdArgs.add("-Dgrinder.script=" + getMainScriptLocation());
String additionalVMArgs = configuration.getAttribute(Constants.ATTR_VM_ARGUMENTS,
(String) null);
cmdArgs.addAll(parseArguments(additionalVMArgs));
if (isDebug) {
cmdArgs.add(GrinderConstants.GRINDER_WEAVER_MAIN_CLASS);
} else {
cmdArgs.add(GrinderConstants.GRINDER_MAIN_CLASS);
}
String grinderPropertiesPath = getGrinderPropertiesPath();
cmdArgs.add(grinderPropertiesPath);
String additionalToolArgs = configuration.getAttribute(
GrinderConstants.GRINDER_TOOL_ADDITIONAL_PARAMETERS, (String) null);
cmdArgs.addAll(parseArguments(additionalToolArgs));
return cmdArgs;
}
private void addGrinderAgentIfNecessary(List<String> cmdArgs) {
if (isDebug) {
String grinderAgent = findGrinderAgent();
if (grinderAgent != null) {
cmdArgs.add("-javaagent:" + grinderAgent);
}
}
}
private String findGrinderAgent() {
String agent = null;
if (pythonpathUsed != null && pythonpathUsed.length() != 0) {
String[] elements = pythonpathUsed.split(File.pathSeparator);
for (String e : elements) {
if (e.endsWith(GrinderConstants.GRINDER_AGENT_JAR_FILENAME)) {
agent = e;
break;
}
}
}
return agent;
}
/**
* Method parses arguments escaping quotes and spaces.
*
* @param arguments arguments as string
* @return collection of arguments
* @throws CoreException if parsing fails
*/
@SuppressWarnings("unchecked")
protected Collection<String> parseArguments(String arguments) throws CoreException {
if (arguments == null) {
return Collections.EMPTY_LIST;
}
return Arrays.asList(DebugPlugin.parseArguments(performStringSubstitution(arguments)));
}
/**
* Validates the current interpreter.
*
* @throws CoreException if interpreter is not jython
*/
private void checkIfNotJython() throws CoreException {
if (!InterpreterInfo.isJythonExecutable(interpreter.toOSString())) {
throw new CoreException(GrinderStonePlugin.makeStatus(IStatus.ERROR,
"The jython jar must be specified as the interpreter to run. Found: "
+ interpreter, null));
}
}
/**
* @return generated classpath as string
* @throws CoreException if weaver is not found
*/
private String generateClasspath() throws CoreException {
String classpath = interpreter.toOSString();
if (isDebug) {
String weaverPath = REF.getFileAbsolutePath(GrinderStonePlugin.getGrinderWeaver());
classpath += (File.pathSeparator + weaverPath);
}
return classpath + File.pathSeparatorChar + getPythonPath();
}
/**
* Method looks for <tt>grinder.properties</tt> path in preferences.
*
* @return path to <tt>grinder.properties</tt>
* @throws CoreException if path cannot be resolved or resolved incorrectly
*/
protected String getGrinderPropertiesPath() throws CoreException {
String grinderPropertiesPath = configuration.getAttribute(
GrinderConstants.ATTR_GRINDER_PROPERTIES_LOCATION, (String) null);
validateGrinderPropertiesPath(grinderPropertiesPath);
grinderPropertiesPath = performStringSubstitution(grinderPropertiesPath);
validateGrinderPropertiesPath(grinderPropertiesPath);
return grinderPropertiesPath;
}
/**
* Method performs string substitution in expression via {@link VariablesPlugin}.
*
* @param expression expression
* @return substituted string
* @throws CoreException if substitution fails
*/
protected String performStringSubstitution(String expression) throws CoreException {
IStringVariableManager varManager = VariablesPlugin.getDefault().getStringVariableManager();
return varManager.performStringSubstitution(expression);
}
/**
* Method validates the given <tt>grinder.properties</tt> path.
*
* @param grinderPropertiesPath resolved path
* @throws CoreException if validation fails
*/
protected void validateGrinderPropertiesPath(String grinderPropertiesPath) throws CoreException {
if (grinderPropertiesPath == null || grinderPropertiesPath.length() == 0) {
throw new CoreException(GrinderStonePlugin.makeStatus(IStatus.ERROR,
"Unable to get location for grinder.properties", null));
}
}
/**
* @return main script location according to some versions of PyDev
*/
protected String getMainScriptLocation() {
String result = null;
Object res = resource;
if (res instanceof IPath) {
result = ((IPath) res).toOSString();
} else if (res instanceof IPath[]) {
IPath[] pathes = ((IPath[]) res);
for (int i = 0; i < pathes.length; i++) {
if (pathes[i] != null) {
result = pathes[0].toOSString();
break;
}
}
}
return result;
}
/**
* Method returns python path.
*
* @return source path to project
* @throws CoreException threw if something wrong
*/
private String getPythonPath() throws CoreException {
IPythonPathNature pythonPathNature = PythonNature.getPythonPathNature(project);
String pyPath = extractSourcePathFromPyProject(pythonPathNature, project);
pyPath = addReferencedJavaProjects(pyPath);
if (isDebug) {
String dLocation = PythonRunnerConfig.getDebugScript();
dLocation = dLocation.substring(0, dLocation.lastIndexOf(File.separatorChar));
pyPath += (File.pathSeparator + dLocation);
String pySrc = getPySrcAbsolutePath();
pyPath += (File.pathSeparator + pySrc);
}
return pyPath + File.pathSeparatorChar + pythonpathUsed;
}
private String addReferencedJavaProjects(String pyPath) {
try {
String pathFromReferencedJavaProjects = new JavaProjectPyPathBuilder(project)
.buildPyPath();
if (pathFromReferencedJavaProjects != null
&& pathFromReferencedJavaProjects.length() > 0) {
pyPath += pathFromReferencedJavaProjects;
}
} catch (Exception e) {
// skip processing if JDT is not present
if (!(e instanceof ClassNotFoundException)) {
GrinderStonePlugin.log(e);
}
} catch (Error e) {
// skip processing if JDT is not present
if (!(e instanceof LinkageError)) {
GrinderStonePlugin.log(e);
}
}
return pyPath;
}
private String extractSourcePathFromPyProject(IPythonPathNature pythonPathNature,
IProject pyProject) throws CoreException {
String pyPath = pythonPathNature.getProjectSourcePath(true);
pyPath = pyPath.replaceAll("\\|", File.pathSeparator);
pyPath = PathUtils.substituteProjectPath(pyProject, pyPath);
String extPath = pythonPathNature.getProjectExternalSourcePath(true);
if (extPath != null && extPath.length() > 0) {
pyPath += File.pathSeparator + extPath.replaceAll("\\|", File.pathSeparator);
}
return pyPath;
}
private String getPySrcAbsolutePath() throws CoreException {
return REF.getFileAbsolutePath(GrinderStonePlugin.getPySrcPath());
}
}