/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.debug.ui.internal.util; import com.google.dart.tools.core.DartCore; import com.google.dart.tools.core.analysis.model.LightweightModel; import com.google.dart.tools.core.dart2js.ProcessRunner; import com.google.dart.tools.core.model.DartModelException; import com.google.dart.tools.debug.core.DartDebugCorePlugin; import com.google.dart.tools.debug.core.DartLaunchConfigWrapper; import com.google.dart.tools.debug.ui.internal.DartDebugUIPlugin; import com.google.dart.tools.debug.ui.internal.DartUtil; import com.google.dart.tools.debug.ui.internal.browser.BrowserLaunchShortcut; import com.google.dart.tools.debug.ui.internal.browser.Messages; import com.google.dart.tools.debug.ui.internal.dartium.DartiumLaunchShortcut; import com.google.dart.tools.debug.ui.internal.mobile.MobileLaunchShortcut; import com.google.dart.tools.debug.ui.internal.server.DartServerLaunchShortcut; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobManager; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.internal.ui.views.console.ProcessConsole; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.debug.ui.IDebugModelPresentation; import org.eclipse.debug.ui.IDebugUIConstants; import org.eclipse.debug.ui.ILaunchShortcut; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.browser.IWebBrowser; import org.eclipse.ui.browser.IWorkbenchBrowserSupport; import org.eclipse.ui.console.ConsolePlugin; import org.eclipse.ui.console.IConsole; import org.eclipse.ui.dialogs.ElementListSelectionDialog; import org.eclipse.ui.ide.IDE; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; /** * A utility class for launching and launch configurations. */ @SuppressWarnings("restriction") public class LaunchUtils { public static final String DARTIUM_LAUNCH_NAME = "Dartium launch"; private static List<ILaunchShortcut> shortcuts; /** * Returns true if the given launch config can be launched w/o waiting on the builder. */ public static boolean canFastLaunch(ILaunchConfiguration config) { DartLaunchConfigWrapper wrapper = new DartLaunchConfigWrapper(config); IProject project = wrapper.getProject(); if (project == null) { return false; } // if pubspec.yaml is not up-to-date, return false IFile pubspecYamlFile = project.getFile(DartCore.PUBSPEC_FILE_NAME); if (pubspecYamlFile.exists()) { IFile pubspecLockFile = project.getFile(DartCore.PUBSPEC_LOCK_FILE_NAME); if (!pubspecLockFile.exists()) { return false; } if (pubspecLockFile.getLocalTimeStamp() < pubspecYamlFile.getLocalTimeStamp()) { return false; } } return true; } /** * Allow the user to choose one from a set of launch configurations. * * @param configList * @return */ public static ILaunchConfiguration chooseConfiguration(List<ILaunchConfiguration> configList) { IDebugModelPresentation labelProvider = DebugUITools.newDebugModelPresentation(); ElementListSelectionDialog dialog = new ElementListSelectionDialog( PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), labelProvider); dialog.setElements(configList.toArray()); dialog.setTitle("Select Dart Application"); dialog.setMessage("&Select existing configuration:"); dialog.setMultipleSelection(false); int result = dialog.open(); labelProvider.dispose(); if (result == Window.OK) { return (ILaunchConfiguration) dialog.getFirstResult(); } return null; } public static ILaunchConfiguration chooseLatest(Collection<ILaunchConfiguration> launches) { long latestTime = 0; ILaunchConfiguration latestLaunch = null; for (ILaunchConfiguration launch : launches) { DartLaunchConfigWrapper wrapper = new DartLaunchConfigWrapper(launch); long time = wrapper.getLastLaunchTime(); if (time > latestTime) { latestTime = time; latestLaunch = launch; } } return latestLaunch; } public static void clearDartiumConsoles() { IConsole[] consoles = ConsolePlugin.getDefault().getConsoleManager().getConsoles(); for (IConsole console : consoles) { if (console instanceof ProcessConsole) { if (console.getName().contains(DARTIUM_LAUNCH_NAME)) { ((ProcessConsole) console).clearConsole(); } } } } public static List<ILaunchConfiguration> getAllLaunches() { try { ILaunchConfiguration[] launchConfigs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(); List<ILaunchConfiguration> validLaunchConfigs = new ArrayList<ILaunchConfiguration>(); for (ILaunchConfiguration config : launchConfigs) { IResource[] resources = config.getMappedResources(); if (resources != null) { for (int i = 0; i < resources.length; i++) { IProject project = resources[i].getProject(); if (project != null && project.exists()) { validLaunchConfigs.add(config); } } } else { validLaunchConfigs.add(config); } } return validLaunchConfigs; } catch (CoreException exception) { DartUtil.logError(exception); return Collections.emptyList(); } } public static ILaunchConfiguration[] getAllLaunchesArray() { List<ILaunchConfiguration> configs = getAllLaunches(); return configs.toArray(new ILaunchConfiguration[configs.size()]); } /** * @return a list of all the launch shortcuts in the system */ public static List<ILaunchShortcut> getAllLaunchShortcuts() { if (shortcuts == null) { shortcuts = new ArrayList<ILaunchShortcut>(); IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint( IDebugUIConstants.PLUGIN_ID, IDebugUIConstants.EXTENSION_POINT_LAUNCH_SHORTCUTS); IConfigurationElement[] infos = extensionPoint.getConfigurationElements(); try { for (IConfigurationElement element : infos) { ILaunchShortcut shortcut = (ILaunchShortcut) element.createExecutableExtension("class"); shortcuts.add(shortcut); } } catch (CoreException ce) { DartUtil.logError(ce); } } return shortcuts; } public static List<ILaunchShortcut> getApplicableLaunchShortcuts(IResource resource) { List<ILaunchShortcut> candidates = new ArrayList<ILaunchShortcut>(); for (ILaunchShortcut shortcut : getAllLaunchShortcuts()) { if (shortcut instanceof ILaunchShortcutExt) { ILaunchShortcutExt handler = (ILaunchShortcutExt) shortcut; if (handler.canLaunch(resource)) { candidates.add(shortcut); } } } return candidates; } public static ILaunchShortcut getBrowserLaunchShortcut() { for (ILaunchShortcut shortcut : getAllLaunchShortcuts()) { if (shortcut instanceof BrowserLaunchShortcut) { return shortcut; } } return null; } public static ILaunchShortcut getDartiumLaunchShortcut() { for (ILaunchShortcut shortcut : getAllLaunchShortcuts()) { if (shortcut instanceof DartiumLaunchShortcut) { return shortcut; } } return null; } public static List<ILaunchConfiguration> getExistingLaunchesFor(IResource resource) { Set<ILaunchConfiguration> configs = new LinkedHashSet<ILaunchConfiguration>(); for (ILaunchShortcut shortcut : getAllLaunchShortcuts()) { if (shortcut instanceof ILaunchShortcutExt) { ILaunchShortcutExt handler = (ILaunchShortcutExt) shortcut; configs.addAll(Arrays.asList(handler.getAssociatedLaunchConfigurations(resource))); } } return new ArrayList<ILaunchConfiguration>(configs); } public static List<ILaunchConfiguration> getLaunchesFor(IProject project) { List<ILaunchConfiguration> launches = new ArrayList<ILaunchConfiguration>(); for (ILaunchConfiguration config : LaunchUtils.getAllLaunches()) { try { if (config.getMappedResources() == null) { continue; } for (IResource resource : config.getMappedResources()) { if (project.equals(resource.getProject())) { if (!launches.contains(config)) { launches.add(config); } } } } catch (CoreException exception) { DartUtil.logError(exception); } } return launches; } /** * Return the best launch configuration to run for the given resource. * * @param resource * @return * @throws DartModelException */ public static ILaunchConfiguration getLaunchFor(IResource resource) throws DartModelException { // If it's a project, find any launches in that project. if (resource instanceof IProject) { ILaunchConfiguration config = getLaunchForProject((IProject) resource); if (config != null) { return config; } } List<ILaunchConfiguration> configs = getExistingLaunchesFor(resource); if (configs.size() > 0) { return chooseLatest(configs); } return null; } public static ILaunchConfiguration getLaunchForProject(IProject project) { List<ILaunchConfiguration> launches = getLaunchesFor(project); if (launches.size() > 0) { return chooseLatest(launches); } return null; } /** * @return a user-consumable long name for the launch config, like "foo.html from foo" */ public static String getLongLaunchName(ILaunchConfiguration config) { DartLaunchConfigWrapper wrapper = new DartLaunchConfigWrapper(config); if (wrapper.getProject() != null) { return config.getName() + " from " + wrapper.getProject().getName(); } else { return config.getName(); } } public static ILaunchShortcut getMobileLaunchShortcut() { for (ILaunchShortcut shortcut : getAllLaunchShortcuts()) { if (shortcut instanceof MobileLaunchShortcut) { return shortcut; } } return null; } public static IResource getSelectedResource(IWorkbenchWindow window) { IWorkbenchPage page = window.getActivePage(); if (page == null) { return null; } IWorkbenchPart part = page.getActivePart(); if (part instanceof IEditorPart) { IEditorPart epart = (IEditorPart) part; return (IResource) epart.getEditorInput().getAdapter(IResource.class); } else if (part != null) { IWorkbenchPartSite site = part.getSite(); if (site != null) { ISelectionProvider provider = site.getSelectionProvider(); if (provider != null) { ISelection selection = provider.getSelection(); if (selection instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) selection; if (!ss.isEmpty()) { Iterator<?> iterator = ss.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); if (next instanceof IResource) { return (IResource) next; } else if (next != null) { IResource resource = (IResource) Platform.getAdapterManager().getAdapter( next, IResource.class); if (resource != null) { return resource; } } } } } } } } if (page.getActiveEditor() != null) { return (IResource) page.getActiveEditor().getEditorInput().getAdapter(IResource.class); } return null; } public static ILaunchShortcut getServerLaunchShortcut() { for (ILaunchShortcut shortcut : getAllLaunchShortcuts()) { if (shortcut instanceof DartServerLaunchShortcut) { return shortcut; } } return null; } /** * Checks whether resource can be launched in Dartium or as JavaScript in browser * * @param file the resource to check * @return */ public static boolean isDartiumOrJsLaunchResource(IFile file) { if (DartCore.isHtmlLikeFileName(file.getName()) && !DartCore.isInBuildDirectory(file.getParent())) { return true; } LightweightModel model = LightweightModel.getModel(); if (model.isClientLibrary(file)) { return true; } return false; } /** * Launches the given launch configuration in the specified mode in a background job. * * @param config the config to launch * @param mode the launch mode */ public static void launch(final ILaunchConfiguration config, final String mode) { // If there are any dirty editors for the given project, save them now. DartLaunchConfigWrapper wrapper = new DartLaunchConfigWrapper(config); IProject project = wrapper.getProject(); if (project != null) { IDE.saveAllEditors(new IResource[] {project}, false); } if (!canFastLaunch(config)) { try { // Wait on any existing builds (i.e., something like provisioning pub). IJobManager jobManager = Job.getJobManager(); jobManager.join(ResourcesPlugin.FAMILY_MANUAL_BUILD, null); jobManager.join(ResourcesPlugin.FAMILY_AUTO_BUILD, null); } catch (OperationCanceledException e) { // user cancelled } catch (InterruptedException e) { DartDebugCorePlugin.logError(e); } } DebugUITools.launch(config, mode); } /** * Launch the given url using the browser specified in the preferences * * @param url * @throws CoreException */ public static void launchInExternalBrowser(final String url) throws CoreException { String browserName = DartDebugCorePlugin.getPlugin().getBrowserName(); if (browserName.length() == 0) { throw new CoreException(new Status( IStatus.ERROR, DartDebugUIPlugin.PLUGIN_ID, "Specify browser to launch in Preferences > Run and Debug")); } List<String> cmd = new ArrayList<String>(); if (DartCore.isMac()) { // use open command on mac cmd.add("/usr/bin/open"); cmd.add("-a"); } cmd.add(browserName); cmd.add(url); if (DartDebugCorePlugin.getPlugin().getBrowserArgs().length() != 0) { if (DartCore.isMac()) { cmd.add("--args"); cmd.add(DartDebugCorePlugin.getPlugin().getBrowserArgs()); } else { cmd.addAll(Arrays.asList(DartDebugCorePlugin.getPlugin().getBrowserArgsAsArray())); } } try { ProcessBuilder builder = new ProcessBuilder(cmd); ProcessRunner runner = new ProcessRunner(builder); runner.runAsync(); runner.await(new NullProgressMonitor(), 500); if (runner.getExitCode() != 0) { if (DartCore.isWindows()) { if (browserName.toLowerCase().indexOf("firefox") != -1) { if (runner.getExitCode() == 1) { // In this case, the application was opened in a new tab successfully. // Don't throw an exception. return; } } } throw new CoreException(new Status( IStatus.ERROR, DartDebugUIPlugin.PLUGIN_ID, "Could not launch browser \"" + browserName + "\" : \n\n" + runner.getStdErr())); } } catch (IOException e) { throw new CoreException(new Status( IStatus.ERROR, DartDebugCorePlugin.PLUGIN_ID, Messages.BrowserLaunchConfigurationDelegate_BrowserNotFound, e)); } } /** * Open the default browser with the given url * * @param url * @throws CoreException */ public static void openBrowser(String url) throws CoreException { IWebBrowser browser = null; try { browser = PlatformUI.getWorkbench().getBrowserSupport().createBrowser( IWorkbenchBrowserSupport.AS_EXTERNAL, "defaultBrowser", "Default Browser", "Browser"); if (browser != null) { final IWebBrowser defaultBrowser = browser; final URL urlToOpen = new URL(url); Display.getDefault().asyncExec(new Runnable() { @Override public void run() { try { defaultBrowser.openURL(urlToOpen); } catch (PartInitException e) { DartDebugCorePlugin.logError( Messages.BrowserLaunchConfigurationDelegate_DefaultBrowserNotFound, e); } } }); } else { throw new CoreException(new Status( IStatus.ERROR, DartDebugCorePlugin.PLUGIN_ID, Messages.BrowserLaunchConfigurationDelegate_DefaultBrowserNotFound)); } } catch (MalformedURLException e) { throw new CoreException(new Status( IStatus.ERROR, DartDebugCorePlugin.PLUGIN_ID, Messages.BrowserLaunchConfigurationDelegate_UrlError)); } } private LaunchUtils() { } }