/** * Copyright (C) 2005 - 2012 Eric Van Dewoestine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.eclim; import java.io.FileInputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.tools.ant.taskdefs.condition.Os; import org.eclim.util.CommandExecutor; import org.eclim.util.IOUtils; import static org.junit.Assert.assertNotNull; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; /** * Utility class to executing eclim commands and returning the results. * * @author Eric Van Dewoestine */ public class Eclim { public static final String TEST_PROJECT = "eclim_unit_test"; private static final String ECLIM = System.getProperty("eclipse.home") + "/eclim"; private static final String PORT = System.getProperty("eclimd.port"); private static final String PRETTY = "-pretty"; private static final String COMMAND = "-command"; private static final JsonParser JSON_PARSER = new JsonParser(); private static String workspace; /** * Executes eclim using the supplied arguments. * <p/> * The "-command" argument will be prepended to the argument array you supply. * * @param args The arguments to pass to eclim. * @return The result of the command execution as a string. */ public static Object execute(String[] args) { return execute(args, -1); } /** * Executes eclim using the supplied arguments. * <p/> * The "-command" argument will be prepended to the argument array you supply. * * @param args The arguments to pass to eclim. * @param timeout Timeout in milliseconds. * @return The result of the command execution as a string. */ public static Object execute(String[] args, long timeout) { assertNotNull("Please configure property eclimd.port", PORT); assertNotNull("Please configure property eclipse.home", ECLIM); String[] arguments = null; if (Os.isFamily(Os.FAMILY_WINDOWS)){ String eclimCmd = ECLIM + ".cmd"; String drive = eclimCmd.substring(0, 2); arguments = new String[3]; arguments[0] = "cmd.exe"; arguments[1] = "/c"; arguments[2] = drive + " && \"" + eclimCmd + "\" --nailgun-port " + PORT + " " + PRETTY + " " + COMMAND + " \"" + StringUtils.join(args, "\" \"") + "\""; }else{ arguments = new String[args.length + 5]; System.arraycopy(args, 0, arguments, 5, args.length); arguments[0] = ECLIM; arguments[1] = "--nailgun-port"; arguments[2] = PORT; arguments[3] = PRETTY; arguments[4] = COMMAND; } System.out.println("Command: " + StringUtils.join(arguments, ' ')); CommandExecutor process = null; try{ process = CommandExecutor.execute(arguments, timeout); }catch(Exception e){ throw new RuntimeException(e); } if(process.getReturnCode() == -1){ process.destroy(); throw new RuntimeException("Command timed out."); } if(process.getReturnCode() != 0){ System.out.println("OUT: " + process.getResult()); System.out.println("ERR: " + process.getErrorMessage()); throw new RuntimeException("Command failed: " + process.getReturnCode()); } String result = process.getResult(); System.out.println("Result: " + result); String error = process.getErrorMessage(); if (!StringUtils.EMPTY.equals(error)){ System.out.println("Error: " + error); } if (result.trim().equals(StringUtils.EMPTY)){ result = "\"\""; } return toType(JSON_PARSER.parse(result)); } public static Object toType(JsonElement json) { // null if(json.isJsonNull()){ return null; // int, double, boolean, String }else if(json.isJsonPrimitive()){ JsonPrimitive prim = json.getAsJsonPrimitive(); if(prim.isBoolean()){ return prim.getAsBoolean(); }else if(prim.isString()){ return prim.getAsString(); }else if(prim.isNumber()){ if(prim.getAsString().indexOf('.') != -1){ return prim.getAsDouble(); } return prim.getAsInt(); } // List }else if(json.isJsonArray()){ ArrayList<Object> type = new ArrayList<Object>(); for(JsonElement element : json.getAsJsonArray()){ type.add(toType(element)); } return type; // Map }else if(json.isJsonObject()){ HashMap<String,Object> type = new HashMap<String,Object>(); for(Map.Entry<String,JsonElement> entry : json.getAsJsonObject().entrySet()){ type.put(entry.getKey(), toType(entry.getValue())); } return type; } return null; } /** * Gets the path to the current workspace. * * @return The workspace path. */ public static String getWorkspace() { if(workspace == null){ workspace = ((String)execute(new String[]{"workspace_dir"})).replace('\\', '/'); } return workspace; } /** * Gets the path to the specified project. * * @param name The project name. * @return The project path. */ @SuppressWarnings("unchecked") public static String getProjectPath(String name) { Object result = execute(new String[]{"project_info", "-p", name}); if (result instanceof Map) { Map<String,String> info = (Map<String,String>)result; if (info.containsKey("path")){ return info.get("path"); } } return null; } /** * Determines if a project with the supplied name exists. * * @return true if the project exists, false otherwise. */ public static boolean projectExists(String name) { return getProjectPath(name) != null; } /** * Constructs a full path for the given project relative file. * * @param file The project relative file path. * @return The absolute path to the file. */ public static String resolveFile(String file) { return resolveFile(TEST_PROJECT, file); } /** * Constructs a full path for the given project relative file. * * @param project The name of the project the file belongs to. * @param file The project relative file path. * @return The absolute path to the file. */ public static String resolveFile(String project, String file) { return new StringBuffer() .append(getProjectPath(project)).append('/') .append(file) .toString(); } /** * Reads the project relative file into a string which is then returned. * * @param project The name of the project the file belongs to. * @param file The project relative file path. * @return The file contents as a string. */ public static String fileToString(String project, String file) { String path = resolveFile(project, file); FileInputStream fin = null; try{ fin = new FileInputStream(path); return IOUtils.toString(fin); }catch(Exception e){ throw new RuntimeException(e); }finally{ IOUtils.closeQuietly(fin); } } }