Package org.epic.debug.local

Source Code of org.epic.debug.local.LocalLaunchConfigurationDelegate

package org.epic.debug.local;

import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.ui.console.IConsole;
import org.epic.core.PerlCore;
import org.epic.core.util.PerlExecutableUtilities;
import org.epic.debug.DebugTarget;
import org.epic.debug.LaunchConfigurationDelegate;
import org.epic.debug.PerlDebugPlugin;
import org.epic.debug.PerlLaunchConfigurationConstants;
import org.epic.debug.PerlTarget;
import org.epic.debug.util.ExecutionArguments;
import org.epic.debug.util.RemotePort;
import org.epic.perleditor.PerlEditorPlugin;
import org.epic.perleditor.preferences.PreferenceConstants;

/**
* Executes launch configurations of type "Perl Local".
*/
public class LocalLaunchConfigurationDelegate
    extends LaunchConfigurationDelegate
{  
    protected void doLaunch(
        ILaunchConfiguration configuration,
        String mode,
        ILaunch launch,
        IProgressMonitor monitor) throws CoreException
    {
        try
        {
            PerlTarget target =
                isDebugMode(launch)
                ? startDebugTarget(configuration, launch, monitor)
                : startRunTarget(configuration, launch, monitor);
           
            launch.addDebugTarget(target);
        }
        catch (CoreException e)
        {
            launch.terminate();
            if (e.getStatus().getCode() != DebugTarget.SESSION_TERMINATED)
                throw e;
        }
    }
   
    public boolean preLaunchCheck(
        ILaunchConfiguration configuration,
        String mode,
        IProgressMonitor monitor) throws CoreException
    {
        if (!PerlEditorPlugin.getDefault().requirePerlInterpreter(true))
        {
            return false;
        }
        else return super.preLaunchCheck(configuration, mode, monitor);
    }
   
    private String[] createCommandLine(ILaunch launch)
        throws CoreException
    {  
        ILaunchConfiguration configuration = launch.getLaunchConfiguration();
       
        String perlParams =
            configuration.getAttribute(
                PerlLaunchConfigurationConstants.ATTR_PERL_PARAMETERS,
                "");
        perlParams = VariablesPlugin.getDefault().getStringVariableManager()
            .performStringSubstitution(perlParams);

        String progParams =
            configuration.getAttribute(
                PerlLaunchConfigurationConstants.ATTR_PROGRAM_PARAMETERS,
                "");
        progParams = VariablesPlugin.getDefault().getStringVariableManager()
            .performStringSubstitution(progParams);

        boolean consoleOutput = configuration.getAttribute(
            IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, true);       
   
        List fCmdList = PerlExecutableUtilities.getPerlCommandLine(
            PerlCore.create(getProject(launch)));
   
        fCmdList.add("-I" + PerlDebugPlugin.getDefault().getInternalDebugInc());
       
        // Add absolute path to local working directory to make
        // perl -d refer to modules in the same directory by their
        // absolute rather than relative paths (relevant when setting
        // breakpoints).
        fCmdList.add("-I" + PerlExecutableUtilities.resolveIncPath(
            getLocalWorkingDir(launch).toFile().getAbsolutePath()));
           
        if (launch.getLaunchMode().equals(ILaunchManager.DEBUG_MODE))
        {
            fCmdList.add("-d");
        }
        if (PerlEditorPlugin.getDefault().getBooleanPreference(
            PreferenceConstants.DEBUG_SHOW_WARNINGS))
        {
            fCmdList.add("-w");
        }
        if (PerlEditorPlugin.getDefault().getBooleanPreference(
            PreferenceConstants.DEBUG_TAINT_MODE))
        {
            fCmdList.add("-T");
        }       
        if (consoleOutput)
        {
            fCmdList.add("-Mautoflush_epic");
        }
        if (perlParams != null && perlParams.length() > 0)
        {
            ExecutionArguments exArgs = new ExecutionArguments(perlParams);
            fCmdList.addAll(exArgs.getProgramArgumentsL());
        }
       
        if (isCygwin())
        {
            IPath cygwinPath = getPathMapper(launch).getDebuggerPath(
                getScriptPath(launch), null);
           
            if (cygwinPath != null) fCmdList.add(cygwinPath.toString());
            else throw new CoreException(new Status(
                Status.ERROR,
                PerlDebugPlugin.getUniqueIdentifier(),
                Status.OK,
                MessageFormat.format(
                    "Could not translate path {0} into a Cygwin path.\n" +
                    "Make sure your Cygwin mounts are configured properly.",
                    new String[] { getScriptPath(launch).toOSString() }),
                null
                ));
        }
        else
            fCmdList.add(getScriptPath(launch).toString());
       
        if (progParams != null && progParams.length() > 0)
        {
            ExecutionArguments exArgs = new ExecutionArguments(progParams);
            fCmdList.addAll(exArgs.getProgramArgumentsL());
        }
   
        return (String[]) fCmdList.toArray(new String[fCmdList.size()]);
    }
   
    private void dumpLaunchDetails(       
        String[] cmdParams,
        String[] env,
        IPath workingDir)
    {
        if (!PerlEditorPlugin.getDefault().getBooleanPreference(
            PreferenceConstants.DEBUG_DEBUG_CONSOLE))
        {
            return;
        }

        StringBuffer buf = new StringBuffer("Starting Perl debugger:\n");
        buf.append("Command line:\n");
        for (int i = 0; i < cmdParams.length; i++)
        {
            buf.append(cmdParams[i]);
            buf.append('\n');
        }
        buf.append("Working directory: ");
        buf.append(workingDir.toFile().getAbsolutePath());
        buf.append("\nEnvironment:\n");
        for (int i = 0; i < env.length; i++)
        {
            buf.append(env[i]);
            buf.append('\n');
        }
        ILog log = PerlDebugPlugin.getDefault().getLog();
        log.log(new Status(
            IStatus.INFO,
            PerlDebugPlugin.getUniqueIdentifier(),
            IStatus.OK,
            buf.toString(),
            null));
    }
   
    /**
     * Returns the default working directory used when none is specified
     * in the launch configuration - the parent directory of the script.
     */
    private File getDefaultWorkingDir(ILaunch launch) throws CoreException
    {
        return getScriptPath(launch).removeLastSegments(1).toFile();
    }
   
    private IPath getLocalWorkingDir(ILaunch launch) throws CoreException
    {
        try
        {       
            File workingDir = verifyWorkingDirectory(
                launch.getLaunchConfiguration());
            if (workingDir == null) workingDir = getDefaultWorkingDir(launch);       
            return Path.fromOSString(workingDir.getAbsolutePath());
        }
        catch (CoreException e)       
        {
            PerlDebugPlugin.getDefault().logError(
                "Could not start Perl interpreter: invalid working directory",
                e);
            throw e;
        }
    }
   
    private IPath getScriptPath(ILaunch launch) throws CoreException
    {
        String scriptFile =
            launch.getLaunchConfiguration().getAttribute(
                PerlLaunchConfigurationConstants.ATTR_STARTUP_FILE,
                "");
   
        return getProject(launch).getFile(new Path(scriptFile)).getLocation();
    }
   
    /**
     * Returns the working directory path specified by the given launch
     * configuration, or <code>null</code> if none.
     *
     * @param configuration  launch configuration
     * @return the working directory path specified by the given launch
     *         configuration, or <code>null</code> if none
     * @exception CoreException
     *            if unable to retrieve the attribute
     */
    private IPath getWorkingDirectoryPath(ILaunchConfiguration configuration) throws CoreException
    {
        String path = configuration.getAttribute(
            PerlLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
            (String) null);

        if (path == null) return null;
        else
        {
            path = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(path);
            return new Path(path);
        }
    }
   
    private Process startPerlInterpreter(
        String[] cmdParams,
        String[] env,
        IPath workingDir) throws CoreException
    {
        try
        {
            Process perlProcess =
                Runtime.getRuntime().exec(
                    cmdParams,
                    env,
                    workingDir.toFile());   
           
            return perlProcess;
        }
        catch (IOException e)
        {
            throw new CoreException(new Status(
                IStatus.ERROR,
                PerlDebugPlugin.getUniqueIdentifier(),
                IStatus.OK,
                "Failed to launch Perl interpreter process; " +
                "inspect log for details",
                e));
        }
    }

    private PerlTarget startDebugTarget(
        ILaunchConfiguration configuration,
        ILaunch launch,
        IProgressMonitor monitor) throws CoreException
    {
        RemotePort debugPort = new RemotePort("DebugTarget.mDebugPort");
        debugPort.startConnect();
       
        IProcess process = startPerlProcess(
            launch, "Perl Debugger", debugPort.getServerPort());

        if (debugPort.waitForConnect(true) != RemotePort.WAIT_OK)
        {
            PerlDebugPlugin.errorDialog(getTimeoutErrorMessage(process));
            launch.terminate();
            return null;
        }
        else
        {           
            return new DebugTarget(
                launch, process, debugPort, getPathMapper(launch));
        }
    }
   
    /**
     * Provides some troubleshooting hints in addition to the generic "timed out" message
     * by examining additional error messages found in the console.
     */
    private String getTimeoutErrorMessage(IProcess process)
    {
      IConsole console = DebugUIPlugin.getDefault().getProcessConsoleManager().getConsole(process);
      if (console instanceof ProcessConsole)
      {
            String consoleContents = ((ProcessConsole) console).getDocument().get();
            if (consoleContents.indexOf("Use of uninitialized value in subroutine dereference at (null) line 1.") != -1 &&
                consoleContents.indexOf("perl5db.pl did not return a true value.") != -1)
            {
                return "Timed out while waiting for Perl debugger connection. " +
                  "The most likely reason is a broken version of PathTools in your Perl installation. " +
                  "You can fix this problem manually by editing a single line in Cwd.pm, as suggested " +
                  "in EPIC bug report 2907155 at SourceForge.";
            }
      }
      return "Timed out while waiting for Perl debugger connection.";
  }

  private IProcess startPerlProcess(
        ILaunch launch, String processName, int debugPort) throws CoreException
    {       
        String[] cmdParams = createCommandLine(launch);       
        String[] env = PerlDebugPlugin.getDebugEnv(launch, debugPort);
        IPath workingDir = getLocalWorkingDir(launch);
               
        dumpLaunchDetails(cmdParams, env, workingDir);
        Process perlProcess =
            startPerlInterpreter(cmdParams, env, workingDir);
       
        Map attr = new HashMap(1);
        attr.put(
            IProcess.ATTR_PROCESS_TYPE,
            PerlLaunchConfigurationConstants.PERL_PROCESS_TYPE);
       
        return DebugPlugin.newProcess(
            launch,
            perlProcess,
            processName,
            attr);
    }
   
    private PerlTarget startRunTarget(
        ILaunchConfiguration configuration,
        ILaunch launch,
        IProgressMonitor monitor) throws CoreException
    {
        IProcess process = startPerlProcess(launch, "Perl Interpreter", -1);
        return new RunLocalTarget(launch, process);
    }
   
    /**
     * Verifies the working directory specified by the given launch
     * configuration exists, and returns the working directory, or
     * <code>null</code> if none is specified.
     *
     * @param configuration  launch configuration
     * @return the working directory specified by the given launch
     *         configuration, or <code>null</code> if none
     * @exception CoreException if unable to retrieve the attribute
     */
    private File verifyWorkingDirectory(ILaunchConfiguration configuration)
        throws CoreException
    {
        IPath path = getWorkingDirectoryPath(configuration);
        if (path == null) return null;
       
        if (path.isAbsolute())
        {
            File dir = new File(path.toOSString());
            if (dir.isDirectory()) return dir;
        }
       
        // If we get here, we assume that the entered path is workspace-relative.
        // This is true for paths that do not start with slash, but also for
        // paths that start with slash to which some variables may evaluate.
        // In any case, we try to locate the working directory in the workspace.

        IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
        if (res instanceof IContainer && res.exists())
            return res.getLocation().toFile();

        throw new CoreException(
            new Status(
                Status.ERROR,
                PerlDebugPlugin.getUniqueIdentifier(),
                Status.OK,
                MessageFormat.format(
                    "Working directory does not exist: {0}",
                    new String[] { path.toString() }),
                null
                ));
    }
}
TOP

Related Classes of org.epic.debug.local.LocalLaunchConfigurationDelegate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.