001/* 002 * (C) Copyright 2006-2010 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * bstefanescu 018 */ 019package org.nuxeo.shell.cmds; 020 021import java.io.File; 022import java.io.FileWriter; 023import java.io.IOException; 024import java.io.InputStream; 025import java.io.PrintWriter; 026import java.util.Collection; 027import java.util.HashMap; 028import java.util.HashSet; 029import java.util.List; 030 031import jline.ANSIBuffer; 032 033import org.nuxeo.shell.Argument; 034import org.nuxeo.shell.Command; 035import org.nuxeo.shell.CommandRegistry; 036import org.nuxeo.shell.CommandType; 037import org.nuxeo.shell.Context; 038import org.nuxeo.shell.Parameter; 039import org.nuxeo.shell.Shell; 040import org.nuxeo.shell.ShellConsole; 041import org.nuxeo.shell.ShellException; 042import org.nuxeo.shell.CommandType.Token; 043import org.nuxeo.shell.cmds.completors.CommandRegistryCompletor; 044import org.nuxeo.shell.fs.FileCompletor; 045import org.nuxeo.shell.fs.FileSystem; 046import org.nuxeo.shell.utils.ANSICodes; 047import org.nuxeo.shell.utils.StringUtils; 048 049/** 050 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 051 */ 052@Command(name = "help", help = "The help command") 053public class Help implements Runnable { 054 055 @Context 056 protected Shell shell; 057 058 @Argument(name = "command", required = false, index = 0, help = "the name of the command to get help for") 059 protected CommandType cmd; 060 061 @Parameter(name = "-export", hasValue = true, completor = FileCompletor.class, help = "If used export all the commands available in a wiki formatto the given file. If adirectory is given the export will be made in file help.wiki in that directory.") 062 protected File export; 063 064 @Parameter(name = "-ns", hasValue = true, completor = CommandRegistryCompletor.class, help = "[optional] - to be used to filter commands by namespaces when generating the documentation. By default all namespaces are dumped.") 065 protected CommandRegistry ns; 066 067 public void run() { 068 ShellConsole console = shell.getConsole(); 069 if (export != null) { 070 if (export.isDirectory()) { 071 export = new File(export, "help.wiki"); 072 } 073 try { 074 if (ns == null) { 075 exportCommands(shell, export); 076 } else { 077 exportRegistry(shell, ns, export); 078 } 079 console.println("Commands wiki exported in " + export); 080 } catch (Throwable t) { 081 throw new ShellException("Failed to export commands wiki", t); 082 } 083 return; 084 } 085 if (cmd == null) { 086 showMainPage(console); 087 } else { 088 console.println(getCommandHelp(cmd, false).toString()); 089 } 090 } 091 092 public void showMainPage(ShellConsole console) { 093 ANSIBuffer buf = shell.newANSIBuffer(); 094 InputStream in = getClass().getClassLoader().getResourceAsStream("META-INF/help.txt"); 095 if (in != null) { 096 try { 097 String content = FileSystem.readContent(in); 098 String versionVar = "${version}"; 099 int i = content.indexOf(versionVar); 100 if (i > -1) { 101 content = content.substring(0, i) + Shell.class.getPackage().getImplementationVersion() 102 + content.substring(i + versionVar.length()); 103 } 104 ANSICodes.appendTemplate(buf, content, false); 105 buf.append(ShellConsole.CRLF); 106 } catch (IOException e) { 107 throw new ShellException(e); 108 } finally { 109 try { 110 in.close(); 111 } catch (IOException e) { 112 e.printStackTrace(); 113 } 114 } 115 } 116 117 console.println(buf.toString()); 118 119 } 120 121 public void exportRegistry(Shell shell, CommandRegistry reg, File file) throws Exception { 122 StringBuilder sb = new StringBuilder(); 123 writeRegistry(reg, sb); 124 PrintWriter w = new PrintWriter(new FileWriter(file)); 125 try { 126 w.println(sb.toString()); 127 } finally { 128 w.close(); 129 } 130 } 131 132 public void exportCommands(Shell shell, File file) throws Exception { 133 HashMap<String, StringBuilder> wikis = new HashMap<String, StringBuilder>(); 134 for (String name : shell.getRegistryNames()) { 135 StringBuilder sb = new StringBuilder(); 136 writeRegistry(shell.getRegistry(name), sb); 137 wikis.put(name, sb); 138 } 139 // sort registries: first global, then local, then remote, exclude 140 // automation? 141 PrintWriter w = new PrintWriter(new FileWriter(file)); 142 try { 143 for (StringBuilder sb : wikis.values()) { 144 w.println(sb.toString()); 145 } 146 } finally { 147 w.close(); 148 } 149 } 150 151 protected void writeRegistry(CommandRegistry reg, StringBuilder sb) { 152 sb.append("{info:title=Namespce: *" + reg.getName() + "*}" + reg.getDescription()); 153 sb.append("{info}\nh1. Index\n{toc:minLevel=2|maxLevel=2}\n\n"); 154 HashSet<String> aliases = new HashSet<String>(); 155 for (CommandType cmd : reg.getLocalCommandTypes()) { 156 if (!aliases.contains(cmd.getName())) { 157 writeCommand(cmd, sb); 158 aliases.add(cmd.getName()); 159 } 160 } 161 } 162 163 protected void writeCommand(CommandType cmd, StringBuilder sb) { 164 ANSIBuffer buf = getCommandHelp(cmd, true); 165 sb.append("h2. ").append(cmd.getName()).append("\n").append(buf.toString(false)); 166 } 167 168 protected ANSIBuffer getCommandHelp(CommandType cmd, boolean wiki) { 169 ANSIBuffer buf = shell.newANSIBuffer(); 170 header(buf, "NAME", wiki).append(ShellConsole.CRLF).append("\t"); 171 buf.append(cmd.getName()).append(" -- ").append(cmd.getHelp()); 172 buf.append(ShellConsole.CRLF).append(ShellConsole.CRLF); 173 header(buf, "SYNTAX", wiki).append(ShellConsole.CRLF).append("\t"); 174 syntax(buf, cmd.getSyntax(), wiki); 175 buf.append(ShellConsole.CRLF).append(ShellConsole.CRLF); 176 177 String[] aliases = cmd.getAliases(); 178 if (aliases != null && aliases.length > 0) { 179 if (aliases != null && aliases.length > 0) { 180 header(buf, "ALIASES", wiki).append(ShellConsole.CRLF).append("\t").append( 181 StringUtils.join(aliases, ", ")); 182 buf.append(ShellConsole.CRLF).append(ShellConsole.CRLF); 183 } 184 } 185 186 List<Token> args = cmd.getArguments(); 187 Collection<Token> opts = cmd.getParameters().values(); 188 189 if (!opts.isEmpty()) { 190 header(buf, "OPTIONS", wiki).append(ShellConsole.CRLF); 191 for (Token tok : opts) { 192 if (wiki) { 193 buf.append("*"); 194 } 195 String flag = tok.isRequired ? " - " : " - [flag] - "; 196 buf.append("\t" + tok.name + flag + tok.help).append(ShellConsole.CRLF); 197 } 198 buf.append(ShellConsole.CRLF); 199 } 200 if (!args.isEmpty()) { 201 header(buf, "ARGUMENTS", wiki).append(ShellConsole.CRLF); 202 for (Token tok : args) { 203 if (wiki) { 204 buf.append("*"); 205 } 206 String flag = tok.isRequired ? " - [required] - " : " - [optional] -"; 207 buf.append("\t" + tok.name + flag + tok.help).append(ShellConsole.CRLF); 208 } 209 buf.append(ShellConsole.CRLF); 210 } 211 212 InputStream in = cmd.getCommandClass().getResourceAsStream(cmd.getCommandClass().getSimpleName() + ".help"); 213 if (in != null) { 214 try { 215 String content = FileSystem.readContent(in); 216 ANSICodes.appendTemplate(buf, content, wiki); 217 buf.append(ShellConsole.CRLF); 218 } catch (IOException e) { 219 throw new ShellException(e); 220 } finally { 221 try { 222 in.close(); 223 } catch (IOException e) { 224 e.printStackTrace(); 225 } 226 } 227 } 228 return buf; 229 } 230 231 protected ANSIBuffer header(ANSIBuffer buf, String text, boolean wiki) { 232 if (wiki) { 233 buf.append("*").append(text).append("*"); 234 } else { 235 buf.bold(text); 236 } 237 return buf; 238 } 239 240 protected ANSIBuffer boldify(ANSIBuffer buf, String text, boolean wiki) { 241 if (wiki) { 242 buf.append("*").append(text).append("*"); 243 } else { 244 buf.bold(text); 245 } 246 return buf; 247 } 248 249 protected ANSIBuffer syntax(ANSIBuffer buf, String syntax, boolean wiki) { 250 if (wiki) { 251 buf.append("{code}").append(syntax).append("{code}"); 252 } else { 253 buf.append(syntax); 254 } 255 return buf; 256 } 257 258 protected void formatCommandForWiki() { 259 260 } 261 262}