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:[email protected]">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 try (InputStream in = getClass().getClassLoader().getResourceAsStream("META-INF/help.txt")) { 095 if (in != null) { 096 String content = FileSystem.readContent(in); 097 String versionVar = "${version}"; 098 int i = content.indexOf(versionVar); 099 if (i > -1) { 100 content = content.substring(0, i) + Shell.class.getPackage().getImplementationVersion() 101 + content.substring(i + versionVar.length()); 102 } 103 ANSICodes.appendTemplate(buf, content, false); 104 buf.append(ShellConsole.CRLF); 105 } 106 } catch (IOException e) { 107 throw new ShellException(e); 108 } 109 110 console.println(buf.toString()); 111 112 } 113 114 public void exportRegistry(Shell shell, CommandRegistry reg, File file) throws Exception { 115 StringBuilder sb = new StringBuilder(); 116 writeRegistry(reg, sb); 117 PrintWriter w = new PrintWriter(new FileWriter(file)); 118 try { 119 w.println(sb.toString()); 120 } finally { 121 w.close(); 122 } 123 } 124 125 public void exportCommands(Shell shell, File file) throws Exception { 126 HashMap<String, StringBuilder> wikis = new HashMap<String, StringBuilder>(); 127 for (String name : shell.getRegistryNames()) { 128 StringBuilder sb = new StringBuilder(); 129 writeRegistry(shell.getRegistry(name), sb); 130 wikis.put(name, sb); 131 } 132 // sort registries: first global, then local, then remote, exclude 133 // automation? 134 PrintWriter w = new PrintWriter(new FileWriter(file)); 135 try { 136 for (StringBuilder sb : wikis.values()) { 137 w.println(sb.toString()); 138 } 139 } finally { 140 w.close(); 141 } 142 } 143 144 protected void writeRegistry(CommandRegistry reg, StringBuilder sb) { 145 sb.append("{info:title=Namespce: *" + reg.getName() + "*}" + reg.getDescription()); 146 sb.append("{info}\nh1. Index\n{toc:minLevel=2|maxLevel=2}\n\n"); 147 HashSet<String> aliases = new HashSet<String>(); 148 for (CommandType cmd : reg.getLocalCommandTypes()) { 149 if (!aliases.contains(cmd.getName())) { 150 writeCommand(cmd, sb); 151 aliases.add(cmd.getName()); 152 } 153 } 154 } 155 156 protected void writeCommand(CommandType cmd, StringBuilder sb) { 157 ANSIBuffer buf = getCommandHelp(cmd, true); 158 sb.append("h2. ").append(cmd.getName()).append("\n").append(buf.toString(false)); 159 } 160 161 protected ANSIBuffer getCommandHelp(CommandType cmd, boolean wiki) { 162 ANSIBuffer buf = shell.newANSIBuffer(); 163 header(buf, "NAME", wiki).append(ShellConsole.CRLF).append("\t"); 164 buf.append(cmd.getName()).append(" -- ").append(cmd.getHelp()); 165 buf.append(ShellConsole.CRLF).append(ShellConsole.CRLF); 166 header(buf, "SYNTAX", wiki).append(ShellConsole.CRLF).append("\t"); 167 syntax(buf, cmd.getSyntax(), wiki); 168 buf.append(ShellConsole.CRLF).append(ShellConsole.CRLF); 169 170 String[] aliases = cmd.getAliases(); 171 if (aliases != null && aliases.length > 0) { 172 header(buf, "ALIASES", wiki).append(ShellConsole.CRLF).append("\t").append(StringUtils.join(aliases, ", ")); 173 buf.append(ShellConsole.CRLF).append(ShellConsole.CRLF); 174 } 175 176 List<Token> args = cmd.getArguments(); 177 Collection<Token> opts = cmd.getParameters().values(); 178 179 if (!opts.isEmpty()) { 180 header(buf, "OPTIONS", wiki).append(ShellConsole.CRLF); 181 for (Token tok : opts) { 182 if (wiki) { 183 buf.append("*"); 184 } 185 String flag = tok.isRequired ? " - " : " - [flag] - "; 186 buf.append("\t" + tok.name + flag + tok.help).append(ShellConsole.CRLF); 187 } 188 buf.append(ShellConsole.CRLF); 189 } 190 if (!args.isEmpty()) { 191 header(buf, "ARGUMENTS", wiki).append(ShellConsole.CRLF); 192 for (Token tok : args) { 193 if (wiki) { 194 buf.append("*"); 195 } 196 String flag = tok.isRequired ? " - [required] - " : " - [optional] -"; 197 buf.append("\t" + tok.name + flag + tok.help).append(ShellConsole.CRLF); 198 } 199 buf.append(ShellConsole.CRLF); 200 } 201 202 try (InputStream in = cmd.getCommandClass().getResourceAsStream(cmd.getCommandClass().getSimpleName() + ".help")) { 203 if (in != null) { 204 String content = FileSystem.readContent(in); 205 ANSICodes.appendTemplate(buf, content, wiki); 206 buf.append(ShellConsole.CRLF); 207 } 208 } catch (IOException e) { 209 throw new ShellException(e); 210 } 211 return buf; 212 } 213 214 protected ANSIBuffer header(ANSIBuffer buf, String text, boolean wiki) { 215 if (wiki) { 216 buf.append("*").append(text).append("*"); 217 } else { 218 buf.bold(text); 219 } 220 return buf; 221 } 222 223 protected ANSIBuffer boldify(ANSIBuffer buf, String text, boolean wiki) { 224 if (wiki) { 225 buf.append("*").append(text).append("*"); 226 } else { 227 buf.bold(text); 228 } 229 return buf; 230 } 231 232 protected ANSIBuffer syntax(ANSIBuffer buf, String syntax, boolean wiki) { 233 if (wiki) { 234 buf.append("{code}").append(syntax).append("{code}"); 235 } else { 236 buf.append(syntax); 237 } 238 return buf; 239 } 240 241 protected void formatCommandForWiki() { 242 243 } 244 245}