Debug session thread and socket leak fixed:
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / externaltools / launchConfigurations / ExternalToolsUtil.java
1 package net.sourceforge.phpdt.externaltools.launchConfigurations;
2
3 /**********************************************************************
4  Copyright (c) 2002 IBM Corp. and others. All rights reserved.
5  This file is made available under the terms of the Common Public License v1.0
6  which accompanies this distribution, and is available at
7  http://www.eclipse.org/legal/cpl-v10.html
8  �
9  Contributors:
10  **********************************************************************/
11
12 import java.io.File;
13 import java.text.MessageFormat;
14 import java.util.Map;
15
16 import net.sourceforge.phpdt.externaltools.internal.model.ExternalToolsPlugin;
17 import net.sourceforge.phpdt.externaltools.internal.model.ExternalToolsModelMessages;
18 import net.sourceforge.phpdt.externaltools.internal.model.VariableContextManager;
19 import net.sourceforge.phpdt.externaltools.internal.registry.ExternalToolMigration;
20 import net.sourceforge.phpdt.externaltools.internal.registry.RefreshScopeVariable;
21 import net.sourceforge.phpdt.externaltools.internal.registry.RefreshScopeVariableRegistry;
22 import net.sourceforge.phpdt.externaltools.model.IExternalToolConstants;
23 import net.sourceforge.phpdt.externaltools.model.ToolUtil;
24 import net.sourceforge.phpdt.externaltools.variable.ExpandVariableContext;
25
26 import org.eclipse.core.resources.IResource;
27 import org.eclipse.core.runtime.CoreException;
28 import org.eclipse.core.runtime.IPath;
29 import org.eclipse.core.runtime.IProgressMonitor;
30 import org.eclipse.core.runtime.IStatus;
31 import org.eclipse.core.runtime.MultiStatus;
32 import org.eclipse.core.runtime.Path;
33 import org.eclipse.core.runtime.Status;
34 import org.eclipse.debug.core.DebugPlugin;
35 import org.eclipse.debug.core.ILaunchConfiguration;
36 import org.eclipse.debug.core.ILaunchConfigurationType;
37 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
38 import org.eclipse.debug.core.ILaunchManager;
39
40 /**
41  * Utilities for external tool launch configurations.
42  * <p>
43  * This class it not intended to be instantiated.
44  * </p>
45  */
46 public class ExternalToolsUtil {
47
48   private static final String LAUNCH_CONFIG_HANDLE = "LaunchConfigHandle"; //$NON-NLS-1$
49
50   /**
51    * Not to be instantiated.
52    */
53   private ExternalToolsUtil() {
54   };
55
56   /**
57    * Throws a core exception with an error status object built from the given message, lower level exception, and error code.
58    * 
59    * @param message
60    *          the status message
61    * @param exception
62    *          lower level exception associated with the error, or <code>null</code> if none
63    * @param code
64    *          error code
65    */
66   protected static void abort(String message, Throwable exception, int code) throws CoreException {
67     throw new CoreException(new Status(IStatus.ERROR, IExternalToolConstants.PLUGIN_ID, code, message, exception));
68   }
69
70   /**
71    * Returns active variable context. The active variable context is used to expand variable expressions. If the workspace is
72    * currently being built, the context is associated with the project being built. Otherwise, the context is associated with the
73    * selected resource.
74    * 
75    * @return active variable context
76    */
77   public static ExpandVariableContext getVariableContext() {
78     return VariableContextManager.getDefault().getVariableContext();
79   }
80
81   /**
82    * Expands and returns the location attribute of the given launch configuration, based on the given variable context. The location
83    * is verified to point to an existing file, in the local file system.
84    * 
85    * @param configuration
86    *          launch configuration
87    * @param context
88    *          context used to expand variables
89    * @return an absolute path to a file in the local file system
90    * @throws CoreException
91    *           if unable to retrieve the associated launch configuration attribute, if unable to resolve any variables, or if the
92    *           resolved location does not point to an existing file in the local file system
93    */
94   public static IPath getLocation(ILaunchConfiguration configuration, ExpandVariableContext context) throws CoreException {
95     String location = configuration.getAttribute(IExternalToolConstants.ATTR_LOCATION, (String) null);
96     if (location == null) {
97       abort(MessageFormat.format(ExternalToolsLaunchConfigurationMessages
98           .getString("ExternalToolsUtil.Location_not_specified_by_{0}_1"), new String[] { configuration.getName() }), null, 0); //$NON-NLS-1$
99     } else {
100       MultiStatus status = new MultiStatus(IExternalToolConstants.PLUGIN_ID, 0, ExternalToolsModelMessages
101           .getString("RunExternalToolAction.runProblem"), null); //$NON-NLS-1$;
102       String expandedLocation = ToolUtil.expandFileLocation(location, context, status);
103       if (status.isOK()) {
104         if (expandedLocation == null || expandedLocation.length() == 0) {
105           String msg = ExternalToolsModelMessages.format(
106               "DefaultRunnerContext.invalidLocation", new Object[] { configuration.getName() }); //$NON-NLS-1$
107           abort(msg, null, 0);
108         } else {
109           File file = new File(expandedLocation);
110           if (file.isFile()) {
111             return new Path(expandedLocation);
112           } else {
113             String msg = ExternalToolsModelMessages.format(
114                 "DefaultRunnerContext.invalidLocation", new Object[] { configuration.getName() }); //$NON-NLS-1$
115             abort(msg, null, 0);
116           }
117         }
118       } else {
119         throw new CoreException(status);
120       }
121     }
122     // execution will not reach here
123     return null;
124   }
125
126   /**
127    * Expands and returns the working directory attribute of the given launch configuration, based on the given variable context.
128    * Returns <code>null</code> if a working directory is not specified. If specified, the working is verified to point to an
129    * existing directory in the local file system.
130    * 
131    * @param configuration
132    *          launch configuration
133    * @param context
134    *          context used to expand variables
135    * @return an absolute path to a direcoty in the local file system, or <code>null</code> if unspecified
136    * @throws CoreException
137    *           if unable to retrieve the associated launch configuration attribute, if unable to resolve any variables, or if the
138    *           resolved location does not point to an existing directory in the local file system
139    */
140   public static IPath getWorkingDirectory(ILaunchConfiguration configuration, ExpandVariableContext context) throws CoreException {
141     String location = configuration.getAttribute(IExternalToolConstants.ATTR_WORKING_DIRECTORY, (String) null);
142     if (location != null) {
143       MultiStatus status = new MultiStatus(IExternalToolConstants.PLUGIN_ID, 0, ExternalToolsModelMessages
144           .getString("RunExternalToolAction.runProblem"), null); //$NON-NLS-1$;
145       String expandedLocation = ToolUtil.expandDirectoryLocation(location, context, status);
146       if (status.isOK()) {
147         if (expandedLocation != null && expandedLocation.length() > 0) {
148           File path = new File(expandedLocation);
149           if (path.isDirectory()) {
150             return new Path(expandedLocation);
151           } else {
152             String msg = ExternalToolsModelMessages.format(
153                 "DefaultRunnerContext.invalidDirectory", new Object[] { configuration.getName() }); //$NON-NLS-1$
154             abort(msg, null, 0);
155           }
156         }
157       } else {
158         throw new CoreException(status);
159       }
160     }
161     return null;
162   }
163
164   /**
165    * Expands and returns the arguments attribute of the given launch configuration, based on the given variable context. Returns
166    * <code>null</code> if arguments are not specified.
167    * 
168    * @param configuration
169    *          launch configuration
170    * @param context
171    *          context used to expand variables
172    * @return an array of resolved arguments, or <code>null</code> if unspecified
173    * @throws CoreException
174    *           if unable to retrieve the associated launch configuration attribute, or if unable to resolve any variables
175    */
176   public static String[] getArguments(ILaunchConfiguration configuration, ExpandVariableContext context) throws CoreException {
177     String args = configuration.getAttribute(IExternalToolConstants.ATTR_TOOL_ARGUMENTS, (String) null);
178     if (args != null) {
179       MultiStatus status = new MultiStatus(IExternalToolConstants.PLUGIN_ID, 0, ExternalToolsModelMessages
180           .getString("RunExternalToolAction.runProblem"), null); //$NON-NLS-1$;
181       String[] expandedArgs = ToolUtil.expandArguments(args, context, status);
182       if (status.isOK()) {
183         return expandedArgs;
184       } else {
185         throw new CoreException(status);
186       }
187     }
188     return null;
189   }
190
191   /**
192    * Returns the refresh scope specified by the given launch configuration or <code>null</code> if none.
193    * 
194    * @param configuration
195    * @return refresh scope
196    * @throws CoreException
197    *           if unable to access the associated attribute
198    */
199   public static String getRefreshScope(ILaunchConfiguration configuration) throws CoreException {
200     return configuration.getAttribute(IExternalToolConstants.ATTR_REFRESH_SCOPE, (String) null);
201   }
202
203   /**
204    * Returns whether the refresh scope specified by the given launch configuration is recursive.
205    * 
206    * @param configuration
207    * @return whether the refresh scope is recursive
208    * @throws CoreException
209    *           if unable to access the associated attribute
210    */
211   public static boolean isRefreshRecursive(ILaunchConfiguration configuration) throws CoreException {
212     return configuration.getAttribute(IExternalToolConstants.ATTR_REFRESH_RECURSIVE, false);
213   }
214
215   /**
216    * Refreshes the resources as specified by the given launch configuration.
217    * 
218    * @param configuration
219    *          launch configuration
220    * @param context
221    *          context used to expand variables
222    * @param monitor
223    *          progress monitor
224    * @throws CoreException
225    *           if an exception occurrs while refreshing resources
226    */
227   public static void refreshResources(ILaunchConfiguration configuration, ExpandVariableContext context, IProgressMonitor monitor)
228       throws CoreException {
229     String scope = getRefreshScope(configuration);
230     if (scope == null)
231       return;
232
233     ToolUtil.VariableDefinition varDef = ToolUtil.extractVariableTag(scope, 0);
234     if (varDef.start == -1 || varDef.end == -1 || varDef.name == null) {
235       String msg = ExternalToolsModelMessages.format(
236           "DefaultRunnerContext.invalidRefreshVarFormat", new Object[] { configuration.getName() }); //$NON-NLS-1$
237       abort(msg, null, 0);
238     }
239
240     RefreshScopeVariableRegistry registry = ExternalToolsPlugin.getDefault().getRefreshVariableRegistry();
241     RefreshScopeVariable variable = registry.getRefreshVariable(varDef.name);
242     if (variable == null) {
243       String msg = ExternalToolsModelMessages.format(
244           "DefaultRunnerContext.noRefreshVarNamed", new Object[] { configuration.getName(), varDef.name }); //$NON-NLS-1$
245       abort(msg, null, 0);
246     }
247
248     int depth = IResource.DEPTH_ZERO;
249     if (isRefreshRecursive(configuration))
250       depth = IResource.DEPTH_INFINITE;
251
252     if (monitor.isCanceled())
253       return;
254
255     IResource[] resources = variable.getExpander().getResources(varDef.name, varDef.argument, context);
256     if (resources == null || resources.length == 0)
257       return;
258
259     monitor.beginTask(ExternalToolsModelMessages.getString("DefaultRunnerContext.refreshResources"), //$NON-NLS-1$
260         resources.length);
261
262     MultiStatus status = new MultiStatus(IExternalToolConstants.PLUGIN_ID, 0, ExternalToolsLaunchConfigurationMessages
263         .getString("ExternalToolsUtil.Exception(s)_occurred_during_refresh._2"), null); //$NON-NLS-1$
264     for (int i = 0; i < resources.length; i++) {
265       if (monitor.isCanceled())
266         break;
267       if (resources[i] != null && resources[i].isAccessible()) {
268         try {
269           resources[i].refreshLocal(depth, null);
270         } catch (CoreException e) {
271           status.merge(e.getStatus());
272         }
273       }
274       monitor.worked(1);
275     }
276
277     monitor.done();
278     if (!status.isOK()) {
279       throw new CoreException(status);
280     }
281   }
282
283   /**
284    * Returns whether this tool is to be run in the background..
285    * 
286    * @param configuration
287    * @return whether this tool is to be run in the background
288    * @throws CoreException
289    *           if unable to access the associated attribute
290    */
291   public static boolean isBackground(ILaunchConfiguration configuration) throws CoreException {
292     return configuration.getAttribute(IExternalToolConstants.ATTR_RUN_IN_BACKGROUND, false);
293   }
294
295   /**
296    * Returns a launch configuration from the given ICommand arguments. If the given arguments are from an old-style external tool,
297    * an unsaved working copy will be created from the arguments and returned.
298    * 
299    * @param commandArgs
300    *          the builder ICommand arguments
301    * @param newName
302    *          a new name for the config if the one in the command is invalid
303    * @return a launch configuration, a launch configuration working copy, or <code>null</code> if not possible.
304    */
305   public static ILaunchConfiguration configFromBuildCommandArgs(Map commandArgs) {
306     String configHandle = (String) commandArgs.get(LAUNCH_CONFIG_HANDLE);
307     if (configHandle == null) {
308       // Probably an old-style external tool. Try to migrate.
309       return ExternalToolMigration.configFromArgumentMap(commandArgs);
310     }
311     try {
312       return DebugPlugin.getDefault().getLaunchManager().getLaunchConfiguration(configHandle);
313     } catch (CoreException e) {
314       return null;
315     }
316   }
317
318   /**
319    * Executes an external progam and saves the LaunchConfiguration under external tools
320    * 
321    * @param command
322    *          external tools command name
323    * @param executable
324    *          executable path i.e.c:\apache\apache.exe
325    * @param arguments
326    *          arguments for this configuration
327    * @param background
328    *          run this configuration in background mode
329    */
330   public static void execute(String command, String executable, String arguments, boolean background) {
331     execute(command, executable, null, arguments, background);
332   }
333   
334   
335   public static void execute(String command, String executable, String workingDirectory, String arguments, boolean background) {
336     ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
337     ILaunchConfigurationType type = manager.getLaunchConfigurationType(IExternalToolConstants.ID_PROGRAM_LAUNCH_CONFIGURATION_TYPE);
338
339     ILaunchConfigurationWorkingCopy wc = null;
340     try {
341       wc = type.newInstance(null, command);
342     } catch (CoreException e) {
343       //some exception handling
344     }
345     wc.setAttribute(IExternalToolConstants.ATTR_LOCATION, executable);
346     if (workingDirectory != null) {
347       wc.setAttribute(IExternalToolConstants.ATTR_WORKING_DIRECTORY, workingDirectory);
348     }
349     if (arguments != null) {
350       wc.setAttribute(IExternalToolConstants.ATTR_TOOL_ARGUMENTS, arguments);
351     }
352     wc.setAttribute(IExternalToolConstants.ATTR_RUN_IN_BACKGROUND, background);
353
354     //          saving will add the configuration to the external tools configurations
355     ILaunchConfiguration config;
356     try {
357       config = wc.doSave();
358       config.launch(ILaunchManager.RUN_MODE, null);
359     } catch (CoreException e) {
360     }
361
362   }
363 }