/******************************************************************************* * Copyright (c) 2009, 2010 Sven Kiera * 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 *******************************************************************************/ package org.phpsrc.eclipse.pti.core.launching; import java.io.File; import java.io.IOException; import java.util.Hashtable; import java.util.TimeZone; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IStreamsProxy; import org.eclipse.debug.ui.IDebugUIConstants; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.php.debug.core.debugger.parameters.IDebugParametersKeys; import org.eclipse.php.internal.debug.core.IPHPDebugConstants; import org.eclipse.php.internal.debug.core.debugger.AbstractDebuggerConfiguration; import org.eclipse.php.internal.debug.core.phpIni.PHPINIUtil; import org.eclipse.php.internal.debug.core.preferences.PHPDebugCorePreferenceNames; import org.eclipse.php.internal.debug.core.preferences.PHPDebuggersRegistry; import org.eclipse.php.internal.debug.core.preferences.PHPexeItem; import org.eclipse.php.internal.debug.ui.PHPDebugUIPlugin; import org.eclipse.swt.widgets.Display; import org.phpsrc.eclipse.pti.core.IPHPCoreConstants; import org.phpsrc.eclipse.pti.core.PHPToolCorePlugin; import org.phpsrc.eclipse.pti.core.listener.IOutputListener; import org.phpsrc.eclipse.pti.core.php.inifile.INIFileEntry; import org.phpsrc.eclipse.pti.core.php.inifile.INIFileModifier; import org.phpsrc.eclipse.pti.ui.Logger; @SuppressWarnings("restriction") public class PHPToolLauncher { public final static String COMMANDLINE_PLACEHOLDER_FILE = "%file%"; //$NON-NLS-1$ public final static String COMMANDLINE_PLACEHOLDER_FOLDER = "%folder%"; //$NON-NLS-1$ private final QualifiedName tool; private final PHPexeItem phpExe; private final IPath phpScript; private final INIFileEntry[] iniEntries; private String commandLineArgs; private boolean printOutput = false; private Hashtable<String, String> attributes = new Hashtable<String, String>(); private final PHPToolExecutableLauncher phpLauncher; private IOutputListener outputListener = new IOutputListener() { public void handleOutput(String output) { Logger.logToConsoleWithoutBreak(output); } }; public PHPToolLauncher(QualifiedName tool, PHPexeItem phpExe, IPath phpScript) { this(tool, phpExe, phpScript, ""); } public PHPToolLauncher(QualifiedName tool, PHPexeItem phpExe, IPath phpScript, String commandLineArgs) { this(tool, phpExe, phpScript, commandLineArgs, new INIFileEntry[0]); } public PHPToolLauncher(QualifiedName tool, PHPexeItem phpExe, IPath phpScript, INIFileEntry[] iniEntries) { this(tool, phpExe, phpScript, "", iniEntries); } /** * * @param phpExe * @param phpScript * @param commandLineArgs * @param iniEntries * @throws NullPointerException */ public PHPToolLauncher(QualifiedName tool, PHPexeItem phpExe, IPath phpScript, String commandLineArgs, INIFileEntry[] iniEntries) { Assert.isNotNull(tool); this.tool = tool; this.phpExe = phpExe; this.phpScript = phpScript; this.commandLineArgs = commandLineArgs; this.iniEntries = iniEntries; phpLauncher = new PHPToolExecutableLauncher(); } public String launch(IFile file) { String phpFileLocation = null; IPath location = file.getLocation(); if (location != null) { phpFileLocation = location.toOSString(); } else { phpFileLocation = file.getFullPath().toString(); } return launch(file.getProject(), phpFileLocation); } public String launch(IProject project) { return launch(project, ""); } public void addOutputListener(IOutputListener listener) { phpLauncher.addOutputListener(listener); } protected String launch(IProject project, String phpFileLocation) { if (phpExe == null) return null; try { if (phpFileLocation == null) { // Could not find target to launch throw new CoreException(new Status(IStatus.ERROR, PHPDebugUIPlugin.ID, IStatus.OK, "Launch target not found", null)); } ILaunchConfiguration config = findLaunchConfiguration(project, phpScript.toOSString(), phpScript.toOSString(), phpExe, ILaunchManager.RUN_MODE, getPHPExeLaunchConfigType()); if (config != null) { ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy(); String arguments = commandLineArgs.replace( COMMANDLINE_PLACEHOLDER_FILE, OperatingSystem.escapeShellFileArg(phpFileLocation)); int lastPos = phpFileLocation.lastIndexOf("\\") != -1 ? phpFileLocation .lastIndexOf("\\") : phpFileLocation.lastIndexOf("/"); String folderPath = lastPos != -1 ? OperatingSystem .escapeShellFileArg(phpFileLocation.substring(0, lastPos)) : ""; arguments = arguments.replace(COMMANDLINE_PLACEHOLDER_FOLDER, folderPath); wc.setAttribute( IDebugParametersKeys.EXE_CONFIG_PROGRAM_ARGUMENTS, arguments); config = wc.doSave(); if (printOutput) { phpLauncher.addOutputListener(outputListener); } IProcess process = phpLauncher.launch(config); IStreamsProxy proxy = process.getStreamsProxy(); String output = proxy.getOutputStreamMonitor().getContents(); // if (printOutput) // Logger.logToConsole(output, true); if (printOutput) { phpLauncher.removeOutputListener(outputListener); } return output; } else { // Could not find launch configuration throw new CoreException( new Status( IStatus.ERROR, PHPDebugUIPlugin.ID, IStatus.OK, "Launch configuration could not be created for the selected file.", null)); } } catch (CoreException ce) { if (printOutput) Logger.logToConsole(ce.getMessage()); final IStatus stat = ce.getStatus(); Display.getDefault().asyncExec(new Runnable() { public void run() { ErrorDialog.openError( PHPToolCorePlugin.getActiveWorkbenchShell(), "Error", "Unable to execute file", stat); } }); } return null; } protected static ILaunchConfigurationType getPHPExeLaunchConfigType() { ILaunchManager lm = DebugPlugin.getDefault().getLaunchManager(); return lm.getLaunchConfigurationType(IPHPCoreConstants.LaunchType); } /** * Locate a configuration to relaunch for the given type. If one cannot be * found, create one. * * @return a re-useable config or <code>null</code> if none */ protected ILaunchConfiguration findLaunchConfiguration(IProject phpProject, String phpPathString, String phpFileFullLocation, PHPexeItem defaultEXE, String mode, ILaunchConfigurationType configType) { ILaunchConfiguration config = null; try { ILaunchConfiguration[] configs = DebugPlugin.getDefault() .getLaunchManager().getLaunchConfigurations(configType); int numConfigs = configs == null ? 0 : configs.length; for (int i = 0; i < numConfigs; i++) { String fileName = configs[i].getAttribute( IPHPDebugConstants.ATTR_FILE, (String) null); String exeName = configs[i].getAttribute( IPHPDebugConstants.ATTR_EXECUTABLE_LOCATION, (String) null); boolean isPti = configs[i].getAttribute( PHPToolCorePlugin.PLUGIN_ID, false); if (isPti && phpPathString.equals(fileName) && defaultEXE.getExecutable().toString() .equals(exeName)) { String iniLocation = configs[i] .getAttribute(IPHPDebugConstants.ATTR_INI_LOCATION, (String) null); String toolName = configs[i] .getAttribute( IPHPToolLaunchConstants.ATTR_PHP_TOOL_QUALIFIED_NAME, (String) null); if (iniLocation == null || !(new File(iniLocation).exists()) || toolName == null || !toolName.equals(tool.toString())) { configs[i].delete(); } else { config = configs[i]; } break; } } if (config == null) { String iniFile = null; File PHPINIFile = createCustomPHPINIFile(config, defaultEXE, iniEntries); if (PHPINIFile != null) iniFile = PHPINIFile.getAbsolutePath().toString(); config = createConfiguration(phpProject, phpPathString, phpFileFullLocation, defaultEXE, configType, iniFile); } } catch (CoreException ce) { Logger.logException(ce); } return config; } public static void deleteAllConfigs(String phpPathString) { if (phpPathString == null) return; ILaunchConfigurationType configType = getPHPExeLaunchConfigType(); try { ILaunchConfiguration[] configs = DebugPlugin.getDefault() .getLaunchManager().getLaunchConfigurations(configType); int numConfigs = configs == null ? 0 : configs.length; for (int i = 0; i < numConfigs; i++) { String fileName = configs[i].getAttribute( IPHPDebugConstants.ATTR_FILE, (String) null); boolean isPti = configs[i].getAttribute( PHPToolCorePlugin.PLUGIN_ID, false); if (isPti && phpPathString.equals(fileName)) { configs[i].delete(); } } } catch (CoreException e) { e.printStackTrace(); } } protected File createCustomPHPINIFile(ILaunchConfiguration config, PHPexeItem defaultEXE, INIFileEntry[] fileEntries) { File oldPHPINIFile = defaultEXE.getINILocation(); if (oldPHPINIFile == null || !oldPHPINIFile.isFile() || !oldPHPINIFile.exists()) { oldPHPINIFile = PHPINIUtil.findPHPIni(defaultEXE.getExecutable() .toString()); } if (oldPHPINIFile == null) { try { String iniLocation = config != null ? config.getAttribute( IPHPDebugConstants.ATTR_INI_LOCATION, (String) null) : null; oldPHPINIFile = iniLocation != null ? new File(iniLocation) : null; } catch (CoreException e) { Logger.logException(e); } } File tmpPHPINIFile; if (oldPHPINIFile != null) tmpPHPINIFile = PHPINIUtil.createTemporaryPHPINIFile(oldPHPINIFile); else tmpPHPINIFile = PHPINIUtil.createTemporaryPHPINIFile(); try { INIFileModifier modifier = new INIFileModifier(tmpPHPINIFile); // Since PHP 5.3 you are *required* to use the date.timezone setting // or the date_default_timezone_set() function. modifier.addEntry("Date", "date.timezone", TimeZone.getDefault() .getID()); if (fileEntries != null && fileEntries.length > 0) { for (INIFileEntry entry : fileEntries) { String newValue = entry.getValue(); if (entry.isAdditional()) { String oldValue = modifier.getEntry(entry.getSection(), entry.getName()); if (oldValue != null) newValue += File.pathSeparator + oldValue; } modifier.addEntry(entry.getSection(), entry.getName(), newValue, true, null); } } modifier.close(); } catch (IOException e) { Logger.logException(e); } return tmpPHPINIFile; } /** * Create & return a new configuration */ protected ILaunchConfiguration createConfiguration(IProject phpProject, String phpPathString, String phpFileFullLocation, PHPexeItem defaultEXE, ILaunchConfigurationType configType, String iniPath) throws CoreException { ILaunchConfiguration config = null; ILaunchConfigurationWorkingCopy wc = configType.newInstance(null, getNewConfigurationName(phpPathString)); // Set the delegate class according to selected executable. wc.setAttribute(PHPDebugCorePreferenceNames.PHP_DEBUGGER_ID, defaultEXE.getDebuggerID()); AbstractDebuggerConfiguration debuggerConfiguration = PHPDebuggersRegistry .getDebuggerConfiguration(defaultEXE.getDebuggerID()); wc.setAttribute( PHPDebugCorePreferenceNames.CONFIGURATION_DELEGATE_CLASS, debuggerConfiguration.getScriptLaunchDelegateClass()); wc.setAttribute(IPHPDebugConstants.ATTR_FILE, phpPathString); wc.setAttribute(IPHPDebugConstants.ATTR_FILE_FULL_PATH, phpFileFullLocation); wc.setAttribute(IPHPDebugConstants.ATTR_EXECUTABLE_LOCATION, defaultEXE .getExecutable().getAbsolutePath().toString()); if (iniPath == null) iniPath = defaultEXE.getINILocation() != null ? defaultEXE .getINILocation().toString() : null; wc.setAttribute(IPHPDebugConstants.ATTR_INI_LOCATION, iniPath); wc.setAttribute(IPHPDebugConstants.RUN_WITH_DEBUG_INFO, false); wc.setAttribute(IDebugParametersKeys.FIRST_LINE_BREAKPOINT, false); wc.setAttribute(IDebugUIConstants.ATTR_LAUNCH_IN_BACKGROUND, false); wc.setAttribute(IDebugUIConstants.ATTR_CAPTURE_IN_CONSOLE, true); wc.setAttribute(PHPToolCorePlugin.PLUGIN_ID, true); wc.setAttribute(IPHPToolLaunchConstants.ATTR_PHP_TOOL_QUALIFIED_NAME, tool.toString()); config = wc.doSave(); return config; } /** * Returns a name for a newly created launch configuration according to the * given file name. In case the name generation fails, return the * "New_configuration" string. * * @param fileName * The original file name that this shortcut shoul execute. * @return The new configuration name, or "New_configuration" in case it * fails for some reason. */ protected static String getNewConfigurationName(String fileName) { String configurationName = "New_configuration"; try { IPath path = Path.fromOSString(fileName); String fileExtention = path.getFileExtension(); String lastSegment = path.lastSegment(); if (lastSegment != null) { if (fileExtention != null) { lastSegment = lastSegment.replaceFirst("." + fileExtention, ""); } configurationName = lastSegment; } } catch (Exception e) { Logger.log(Logger.WARNING, "Could not generate configuration name for " + fileName + ".\nThe default name will be used.", e); } configurationName = "pti_" + configurationName; return DebugPlugin.getDefault().getLaunchManager() .generateUniqueLaunchConfigurationNameFrom(configurationName); } public void setCommandLineArgs(String commandLineArgs) { this.commandLineArgs = commandLineArgs; } public void setPrintOuput(boolean printOutput) { this.printOutput = printOutput; } public void setAttribute(String key, String value) { attributes.put(key, value); } public String getAttribute(String key) { return attributes.get(key); } }