/******************************************************************************* * Copyright (c) 2006 RadRails.org and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package com.aptana.rdt.internal.rake; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.rubypeople.rdt.launching.IRubyLaunchConfigurationConstants; import org.rubypeople.rdt.launching.RubyRuntime; import com.aptana.rdt.rake.IRakeHelper; import com.aptana.rdt.rake.RakePlugin; /** * @author mkent * @author cwilliams */ public class RakeTasksHelper implements IRakeHelper { private Map<String, String> fCachedTasks; private IProject fLastProject; private static RakeTasksHelper fgInstance; private RakeTasksHelper() { } public static IRakeHelper getInstance() { if (fgInstance == null) { fgInstance = new RakeTasksHelper(); } return fgInstance; } public void runRakeTask(IProject project, String task, String parameters, IProgressMonitor monitor) { if (monitor == null) monitor = new NullProgressMonitor(); if (monitor.isCanceled()) return; try { ILaunchConfiguration config = run(project, task, parameters); if (monitor.isCanceled()) return; config.launch(ILaunchManager.RUN_MODE, monitor); } catch (CoreException e) { RakePlugin.log("Error running rake task", e); } } public ILaunchConfiguration run(IProject project, String task, String parameters) { Map<String, String> envMap = new HashMap<String, String>(); if (parameters.contains("RAILS_ENV=")) { String value = parameters.substring(parameters.indexOf("RAILS_ENV=") + 10); if (value.indexOf(' ') != -1) { value = value.substring(0, value.indexOf(' ')); } envMap.put("RAILS_ENV", value); } String command = task + " " + parameters; try { ILaunchConfigurationWorkingCopy wc = RubyRuntime.createBasicLaunch(RakePlugin.getDefault().getRakePath(), command, project, getWorkingDirectory(project)); Map<String, String> map = new HashMap<String, String>(); map.put(IRubyLaunchConfigurationConstants.ATTR_RUBY_COMMAND, "ruby"); wc.setAttribute(IRubyLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE_SPECIFIC_ATTRS_MAP, map); wc.setAttribute(IRubyLaunchConfigurationConstants.ATTR_TERMINAL_COMMAND, "rake " + command); wc.setAttribute(IRubyLaunchConfigurationConstants.ATTR_USE_TERMINAL, "org.radrails.rails.shell"); // use // rails // shell // if // it's // available if (envMap != null && !envMap.isEmpty()) { wc.setAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true); wc.setAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, envMap); } return wc.doSave(); } catch (CoreException e) { RakePlugin.log("Error running rake task", e); } return null; } private static String getWorkingDirectory(IProject project) { if (project == null) return null; try { RakeFileFinder finder = new RakeFileFinder(); project.accept(finder, IResource.NONE); File workingDir = finder.getWorkingDirectory(); if (workingDir != null) return workingDir.getAbsolutePath(); } catch (CoreException e) { RakePlugin.log(e); } return project.getLocation().toOSString(); } /** * Gets the rake tasks for the passed in project * * @param project * The IProject to gather rake tasks for * @return a Map of rake task names to their descriptions */ public Map<String, String> getTasks(IProject project, IProgressMonitor monitor) { return getTasks(project, false, monitor); } /** * Gets the rake tasks for the passed in project * * @param project * The IProject to gather rake tasks for * @param force * Whether or not to force a refresh (don't grab cached value) * @return a Map of rake task names to their descriptions */ public Map<String, String> getTasks(IProject project, boolean force, IProgressMonitor monitor) { if (!force && projectHasntChanged(project) && haveCachedTasks()) { return fCachedTasks; } if (monitor == null) monitor = new NullProgressMonitor(); fLastProject = project; fCachedTasks = null; try { if (monitor.isCanceled()) return Collections.emptyMap(); BufferedReader bufReader = new BufferedReader(new StringReader(getTasksText(project, getWorkingDirectory(project)))); Pattern pat = Pattern.compile("^rake\\s+([\\w:]+)\\s+#\\s+(.+)$"); String line = null; Map<String, String> tasks = new HashMap<String, String>(); while ((line = bufReader.readLine()) != null) { Matcher mat = pat.matcher(line); if (mat.matches()) { tasks.put(mat.group(1), mat.group(2)); } } if (tasks.isEmpty()) return new HashMap<String, String>(); fCachedTasks = Collections.unmodifiableMap(tasks); return fCachedTasks; } catch (IOException e) { RakePlugin.log("Error parsing rake tasks", e); } return new HashMap<String, String>(); } private boolean haveCachedTasks() { return (fCachedTasks != null && !fCachedTasks.isEmpty()); } private boolean projectHasntChanged(IProject selected) { return selected != null && selected.equals(fLastProject); } private static String getTasksText(IProject project, String workingDirectory) { try { String rakePath = RakePlugin.getDefault().getRakePath(); if (project != null && rakePath != null && rakePath.trim().length() > 0) { ILaunchConfigurationWorkingCopy wc = RubyRuntime.createBasicLaunch(rakePath, "--tasks", project, workingDirectory); File file = getRakeTasksFile(project); String result = RubyRuntime.launchInBackgroundAndRead(wc.doSave(), file); if (result == null) return ""; return result; } } catch (CoreException e) { RakePlugin.log("Error listing rake tasks", e); } return ""; } private static File getRakeTasksFile(IProject proj) { File file = RakePlugin.getDefault().getStateLocation().append("rake").append(proj.getName() + "_tasks.txt") .toFile(); try { file.getParentFile().mkdirs(); file.createNewFile(); } catch (IOException e) { // ignore } return file; } }