1
2 import org.apache.maven.plugin.AbstractMojo;
3 import org.apache.maven.plugin.MojoExecutionException;
4 import org.codehaus.plexus.util.ReaderFactory;
5 import org.codehaus.plexus.util.StringUtils;
6 import org.codehaus.plexus.util.xml.Xpp3Dom;
7 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
8 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
9
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
15
16
17
18
19
20
21
22
23
24
25 public class HelpMojo
26 extends AbstractMojo
27 {
28
29
30
31
32
33
34 private boolean detail;
35
36
37
38
39
40
41
42 private java.lang.String goal;
43
44
45
46
47
48
49
50 private int lineLength;
51
52
53
54
55
56
57
58 private int indentSize;
59
60
61 private static final String PLUGIN_HELP_PATH = "/META-INF/maven/org.apache.maven.plugins/maven-install-plugin/plugin-help.xml";
62
63 private Xpp3Dom build()
64 throws MojoExecutionException
65 {
66 getLog().debug( "load plugin-help.xml: " + PLUGIN_HELP_PATH );
67 InputStream is = getClass().getResourceAsStream( PLUGIN_HELP_PATH );
68 try
69 {
70 return Xpp3DomBuilder.build( ReaderFactory.newXmlReader( is ) );
71 }
72 catch ( XmlPullParserException e )
73 {
74 throw new MojoExecutionException( e.getMessage(), e );
75 }
76 catch ( IOException e )
77 {
78 throw new MojoExecutionException( e.getMessage(), e );
79 }
80 }
81
82
83
84
85 public void execute()
86 throws MojoExecutionException
87 {
88 if ( lineLength <= 0 )
89 {
90 getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." );
91 lineLength = 80;
92 }
93 if ( indentSize <= 0 )
94 {
95 getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." );
96 indentSize = 2;
97 }
98
99 Xpp3Dom pluginElement = build();
100
101 StringBuilder sb = new StringBuilder();
102 String name = pluginElement.getChild( "name" ).getValue();
103 String version = pluginElement.getChild( "version" ).getValue();
104 String id = pluginElement.getChild( "groupId" ).getValue() + ":" + pluginElement.getChild( "artifactId" ).getValue()
105 + ":" + version;
106 if ( StringUtils.isNotEmpty( name ) && !name.contains( id ) )
107 {
108 append( sb, name + " " + version, 0 );
109 }
110 else
111 {
112 if ( StringUtils.isNotEmpty( name ) )
113 {
114 append( sb, name, 0 );
115 }
116 else
117 {
118 append( sb, id, 0 );
119 }
120 }
121 append( sb, pluginElement.getChild( "description" ).getValue(), 1 );
122 append( sb, "", 0 );
123
124
125 String goalPrefix = pluginElement.getChild( "goalPrefix" ).getValue();
126
127 Xpp3Dom[] mojos = pluginElement.getChild( "mojos" ).getChildren( "mojo" );
128
129 if ( goal == null || goal.length() <= 0 )
130 {
131 append( sb, "This plugin has " + mojos.length + ( mojos.length > 1 ? " goals:" : " goal:" ) , 0 );
132 append( sb, "", 0 );
133 }
134
135 for ( Xpp3Dom mojo : mojos )
136 {
137 writeGoal( sb, goalPrefix, mojo );
138 }
139
140 if ( getLog().isInfoEnabled() )
141 {
142 getLog().info( sb.toString() );
143 }
144 }
145
146 private String getValue( Xpp3Dom mojo, String child )
147 {
148 Xpp3Dom elt = mojo.getChild( child );
149 return ( elt == null ) ? "" : elt.getValue();
150 }
151
152 private void writeGoal( StringBuilder sb, String goalPrefix, Xpp3Dom mojo )
153 {
154 String mojoGoal = mojo.getChild( "goal" ).getValue();
155 Xpp3Dom configurationElement = mojo.getChild( "configuration" );
156
157 if ( goal == null || goal.length() <= 0 || mojoGoal.equals( goal ) )
158 {
159 append( sb, goalPrefix + ":" + mojoGoal, 0 );
160 Xpp3Dom deprecated = mojo.getChild( "deprecated" );
161 if ( ( deprecated != null ) && StringUtils.isNotEmpty( deprecated.getValue() ) )
162 {
163 append( sb, "Deprecated. " + deprecated, 1 );
164 if ( detail )
165 {
166 append( sb, "", 0 );
167 append( sb, getValue( mojo, "description" ), 1 );
168 }
169 }
170 else
171 {
172 append( sb, getValue( mojo, "description" ), 1 );
173 }
174 append( sb, "", 0 );
175
176 if ( detail )
177 {
178 Xpp3Dom[] parameters = mojo.getChild( "parameters" ).getChildren( "parameter" );
179 append( sb, "Available parameters:", 1 );
180 append( sb, "", 0 );
181
182 for ( Xpp3Dom parameter : parameters )
183 {
184 writeParameter( sb, parameter, configurationElement );
185 }
186 }
187 }
188 }
189
190 private void writeParameter( StringBuilder sb, Xpp3Dom parameter, Xpp3Dom configurationElement )
191 {
192 String parameterName = parameter.getChild( "name" ).getValue();
193 String parameterDescription = parameter.getChild( "description" ).getValue();
194
195 Xpp3Dom fieldConfigurationElement = configurationElement.getChild( parameterName );
196
197 String parameterDefaultValue = "";
198 if ( fieldConfigurationElement != null && fieldConfigurationElement.getValue() != null )
199 {
200 parameterDefaultValue = " (Default: " + fieldConfigurationElement.getAttribute( "default-value" ) + ")";
201 }
202 append( sb, parameterName + parameterDefaultValue, 2 );
203 Xpp3Dom deprecated = parameter.getChild( "deprecated" );
204 if ( ( deprecated != null ) && StringUtils.isNotEmpty( deprecated.getValue() ) )
205 {
206 append( sb, "Deprecated. " + deprecated.getValue(), 3 );
207 append( sb, "", 0 );
208 }
209 append( sb, parameterDescription, 3 );
210 if ( "true".equals( parameter.getChild( "required" ).getValue() ) )
211 {
212 append( sb, "Required: Yes", 3 );
213 }
214 Xpp3Dom expression = parameter.getChild( "expression" );
215 if ( ( expression != null ) && StringUtils.isNotEmpty( expression.getValue() ) )
216 {
217 append( sb, "Expression: " + expression.getValue(), 3 );
218 }
219
220 append( sb, "", 0 );
221 }
222
223
224
225
226
227
228
229
230
231
232 private static String repeat( String str, int repeat )
233 {
234 StringBuilder buffer = new StringBuilder( repeat * str.length() );
235
236 for ( int i = 0; i < repeat; i++ )
237 {
238 buffer.append( str );
239 }
240
241 return buffer.toString();
242 }
243
244
245
246
247
248
249
250
251
252 private void append( StringBuilder sb, String description, int indent )
253 {
254 for ( String line : toLines( description, indent, indentSize, lineLength ) )
255 {
256 sb.append( line ).append( '\n' );
257 }
258 }
259
260
261
262
263
264
265
266
267
268
269
270 private static List<String> toLines( String text, int indent, int indentSize, int lineLength )
271 {
272 List<String> lines = new ArrayList<String>();
273
274 String ind = repeat( "\t", indent );
275
276 String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
277
278 for ( String plainLine : plainLines )
279 {
280 toLines( lines, ind + plainLine, indentSize, lineLength );
281 }
282
283 return lines;
284 }
285
286
287
288
289
290
291
292
293
294 private static void toLines( List<String> lines, String line, int indentSize, int lineLength )
295 {
296 int lineIndent = getIndentLevel( line );
297 StringBuilder buf = new StringBuilder( 256 );
298
299 String[] tokens = line.split( " +" );
300
301 for ( String token : tokens )
302 {
303 if ( buf.length() > 0 )
304 {
305 if ( buf.length() + token.length() >= lineLength )
306 {
307 lines.add( buf.toString() );
308 buf.setLength( 0 );
309 buf.append( repeat( " ", lineIndent * indentSize ) );
310 }
311 else
312 {
313 buf.append( ' ' );
314 }
315 }
316
317 for ( int j = 0; j < token.length(); j++ )
318 {
319 char c = token.charAt( j );
320 if ( c == '\t' )
321 {
322 buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
323 }
324 else if ( c == '\u00A0' )
325 {
326 buf.append( ' ' );
327 }
328 else
329 {
330 buf.append( c );
331 }
332 }
333 }
334 lines.add( buf.toString() );
335 }
336
337
338
339
340
341
342
343 private static int getIndentLevel( String line )
344 {
345 int level = 0;
346 for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
347 {
348 level++;
349 }
350 for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
351 {
352 if ( line.charAt( i ) == '\t' )
353 {
354 level++;
355 break;
356 }
357 }
358 return level;
359 }
360 }