package com.aptana.radrails.cloud.shell; 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.resources.IResourceProxy; import org.eclipse.core.resources.IResourceProxyVisitor; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.rubypeople.rdt.core.RubyCore; import org.rubypeople.rdt.launching.RubyRuntime; import com.aptana.ide.core.IdeLog; import com.aptana.radrails.cloud.Activator; import com.aptana.radrails.cloud.internal.CloudUtil; import com.aptana.rdt.AptanaRDTPlugin; class ApCloud { private IProject fLastProject; private Map<String, String> fCachedTasks; /** * 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) { if (!force && projectHasntChanged(project) && haveCachedTasks()) { return fCachedTasks; } fLastProject = project; fCachedTasks = null; try { BufferedReader bufReader = new BufferedReader(new StringReader(getTasksText(project, getWorkingDirectory(project)))); Pattern pat = Pattern.compile("^cap\\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) { IdeLog.logError(Activator.getDefault(), "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 = buildBinExecutablePath(AptanaCloudCommandProvider.APCLOUD); if (project != null && rakePath != null && rakePath.trim().length() > 0) { ILaunchConfigurationWorkingCopy wc = RubyRuntime.createBasicLaunch(rakePath, AptanaCloudCommandProvider.LIST_TASKS_SWITCH, project, workingDirectory); File file = getRakeTasksFile(project); String result = RubyRuntime.launchInBackgroundAndRead(wc.doSave(), file); if (result == null) return ""; return result; } } catch (CoreException e) { IdeLog.logError(Activator.getDefault(), "Error listing apcloud tasks", e); } return ""; } private static File getRakeTasksFile(IProject proj) { File file = Activator.getDefault().getStateLocation().append(AptanaCloudCommandProvider.APCLOUD).append( proj.getName() + "_tasks.txt").toFile(); try { file.getParentFile().mkdirs(); file.createNewFile(); } catch (IOException e) { // ignore } return file; } private static String getWorkingDirectory(IProject project) { if (project == null) return null; try { CapfileFinder finder = new CapfileFinder(); project.accept(finder, IResource.FOLDER); File workingDir = finder.getWorkingDirectory(); if (workingDir != null) return workingDir.getAbsolutePath(); } catch (CoreException e) { IdeLog.logError(Activator.getDefault(), e.getMessage(), e); } return project.getLocation().toOSString(); } private static String buildBinExecutablePath(String command) { // Check the bin directory where ruby executable is. IPath path = RubyRuntime.checkInterpreterBin(command); if (path != null && path.toFile().exists()) return path.toOSString(); // try a bin subdir of gem install directory, then try system path path = AptanaRDTPlugin.checkBinDir(command); if (path != null && path.toFile().exists()) return path.toOSString(); // try system path path = RubyCore.checkSystemPath(command); if (path != null && path.toFile().exists()) return path.toOSString(); return null; } private static class CapfileFinder implements IResourceProxyVisitor { private static final String CAPFILE = CloudUtil.CAPFILE; private File workingDirectory; public boolean visit(IResourceProxy proxy) throws CoreException { if (proxy.getType() == IResource.FILE) { IPath path = proxy.requestFullPath(); if (path.lastSegment().equalsIgnoreCase(CAPFILE)) { workingDirectory = path.removeLastSegments(1).toFile(); } } return workingDirectory == null && (proxy.getType() == IResource.FOLDER || proxy.getType() == IResource.PROJECT || proxy.getType() == IResource.ROOT); } public File getWorkingDirectory() { return workingDirectory; } } }