/** * 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.command; import java.io.PrintStream; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.SystemUtils; import org.eclim.Services; import org.eclim.logging.Logger; import org.eclipse.swt.widgets.Display; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.martiansoftware.nailgun.NGContext; /** * Entry point for client invocation. * * @author Eric Van Dewoestine */ public class Main { private static final Logger logger = Logger.getLogger(Main.class); /** * Main method for executing the client. * * @param context The nailgun context. */ public static final void nailMain(final NGContext context) { try{ logger.debug("args: " + Arrays.toString(context.getArgs())); ArrayList<String> arguments = new ArrayList<String>(); for(String arg : context.getArgs()){ if(arg.startsWith("-D")){ String[] prop = StringUtils.split(arg.substring(2), '='); System.setProperty(prop[0], prop[1]); }else{ arguments.add(arg); } } if (arguments.isEmpty() || arguments.contains("-?")){ int index = arguments.indexOf("-?"); String cmd = arguments.size() > index + 1 ? arguments.get(index + 1) : null; usage(cmd, context.out); System.exit(arguments.isEmpty() ? 1 : 0); } Options options = new Options(); final CommandLine commandLine = options.parse( (String[])arguments.toArray(new String[arguments.size()])); String commandName = commandLine.getValue(Options.COMMAND_OPTION); logger.debug("Main - command: {}", commandName); final Command command = commandLine.getCommand(); command.setContext(context); final Object[] results = new Object[1]; Display.getDefault().syncExec(new Runnable(){ public void run() { try{ results[0] = command.execute(commandLine); }catch(Exception e){ results[0] = e; logger.error("Command failed", e); }finally{ command.cleanup(commandLine); } } }); Object result = results[0]; if (result != null){ if (result instanceof Throwable){ throw (Throwable)result; } GsonBuilder builder = new GsonBuilder(); if (commandLine.hasOption(Options.PRETTY_OPTION)){ builder = builder.setPrettyPrinting(); } if (commandLine.hasOption(Options.EDITOR_OPTION) && commandLine.getValue(Options.EDITOR_OPTION).equals("vim")) { builder = builder .registerTypeAdapter(Boolean.TYPE, new BooleanSerializer()) .registerTypeAdapter(Boolean.class, new BooleanSerializer()); } context.out.println(builder.create().toJson(result)); } }catch(ParseException e){ context.out.println( Services.getMessage(e.getClass().getName(), e.getMessage())); logger.debug("Main - exit on error"); System.exit(1); }catch(Throwable e){ logger.debug("Command triggered exception: " + Arrays.toString(context.getArgs()), e); e.printStackTrace(context.err); logger.debug("Main - exit on error"); System.exit(1); } } public static void usage(String cmd, PrintStream out) { ArrayList<org.eclim.annotation.Command> commands = new ArrayList<org.eclim.annotation.Command>(); for (Class<? extends Command> command : Services.getCommandClasses()){ commands.add(command.getAnnotation(org.eclim.annotation.Command.class)); } Collections.sort(commands, new Comparator<org.eclim.annotation.Command>(){ public int compare( org.eclim.annotation.Command o1, org.eclim.annotation.Command o2) { return o1.name().compareTo(o2.name()); } }); boolean cmdFound = cmd == null; if (cmd == null){ String osOpts = StringUtils.EMPTY; if (SystemUtils.IS_OS_UNIX){ osOpts = " [-f eclimrc] [--nailgun-port port]"; } out.println("Usage: eclim" + osOpts + " -command command [args]"); out.println(" To view a full list of available commands:"); out.println(" eclim -? commands"); out.println(" To view info for a specific command:"); out.println(" eclim -? <command_name>"); out.println(" Ex."); out.println(" eclim -? project_create"); }else if(cmd.equals("commands")){ out.println("Available Commands:"); }else{ out.println("Requested Command:"); } for (org.eclim.annotation.Command command : commands){ if (cmd == null || (!cmd.equals(command.name()) && !cmd.equals("commands"))){ continue; } cmdFound = true; Collection<Option> options = new Options() .parseOptions(command.options()); StringBuffer opts = new StringBuffer(); Iterator<Option> iterator = options.iterator(); for (int ii = 0; iterator.hasNext(); ii++){ Option option = iterator.next(); opts.append(option.isRequired() ? " " : " ["); opts.append('-').append(option.getOpt()); if (option.hasArg()){ opts.append(' ').append(option.getLongOpt()); } if (!option.isRequired()){ opts.append(']'); } // wrap every 4 options if ((ii + 1) % 4 == 0 && ii != options.size() - 1){ opts.append(StringUtils.rightPad("\n", command.name().length() + 5)); } } StringBuffer info = new StringBuffer() .append(" ").append(command.name()).append(opts); out.println(info); if (!command.description().equals(StringUtils.EMPTY)){ out.println(" " + command.description()); } } if (!cmdFound){ out.println(" No Such Command: " + cmd); } } private static class BooleanSerializer implements JsonSerializer<Boolean> { public JsonElement serialize( Boolean bool, Type typeOfSrc, JsonSerializationContext context) { // vim doesn't have a boolean type, so use an int. return new JsonPrimitive(bool.booleanValue() ? 1 : 0); } } }