001package org.andromda.maven.plugin.bootstrap;
002
003import java.util.ArrayList;
004import java.util.Iterator;
005import java.util.List;
006
007import org.apache.maven.plugin.AbstractMojo;
008import org.apache.maven.plugin.MojoExecutionException;
009
010/**
011 * Display help information on andromda-bootstrap-plugin.<br/> Call <pre>  mvn andromda-bootstrap:help -Ddetail=true -Dgoal=&lt;goal-name&gt;</pre> to display parameter details.
012 *
013 * @version generated on Thu Sep 18 15:54:13 EDT 2014
014 * @author org.apache.maven.tools.plugin.generator.PluginHelpGenerator (version 2.9)
015 * @goal help
016 * @requiresProject false
017 * @threadSafe
018 */
019public class HelpMojo
020    extends AbstractMojo
021{
022    /**
023     * If <code>true</code>, display all settable properties for each goal.
024     * 
025     * @parameter expression="${detail}" default-value="false"
026     */
027    private boolean detail;
028
029    /**
030     * The name of the goal for which to show help. If unspecified, all goals will be displayed.
031     * 
032     * @parameter expression="${goal}"
033     */
034    private java.lang.String goal;
035
036    /**
037     * The maximum length of a display line, should be positive.
038     * 
039     * @parameter expression="${lineLength}" default-value="80"
040     */
041    private int lineLength;
042
043    /**
044     * The number of spaces per indentation level, should be positive.
045     * 
046     * @parameter expression="${indentSize}" default-value="2"
047     */
048    private int indentSize;
049
050
051    /** {@inheritDoc} */
052    public void execute()
053        throws MojoExecutionException
054    {
055        if ( lineLength <= 0 )
056        {
057            getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." );
058            lineLength = 80;
059        }
060        if ( indentSize <= 0 )
061        {
062            getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." );
063            indentSize = 2;
064        }
065
066        StringBuffer sb = new StringBuffer();
067
068        append( sb, "org.andromda.maven.plugins:andromda-bootstrap-plugin:3.5-SNAPSHOT", 0 );
069        append( sb, "", 0 );
070
071        append( sb, "AndroMDA Bootstrap Plugin", 0 );
072        append( sb, "A plugin used to run AndroMDA in \'bootstrap\' mode", 1 );
073        append( sb, "", 0 );
074
075        if ( goal == null || goal.length() <= 0 )
076        {
077            append( sb, "This plugin has 3 goals:", 0 );
078            append( sb, "", 0 );
079        }
080
081        if ( goal == null || goal.length() <= 0 || "help".equals( goal ) )
082        {
083            append( sb, "andromda-bootstrap:help", 0 );
084            append( sb, "Display help information on andromda-bootstrap-plugin.\nCall\n\u00a0\u00a0mvn\u00a0andromda-bootstrap:help\u00a0-Ddetail=true\u00a0-Dgoal=<goal-name>\nto display parameter details.", 1 );
085            append( sb, "", 0 );
086            if ( detail )
087            {
088                append( sb, "Available parameters:", 1 );
089                append( sb, "", 0 );
090
091                append( sb, "detail (Default: false)", 2 );
092                append( sb, "If true, display all settable properties for each goal.", 3 );
093                append( sb, "Expression: ${detail}", 3 );
094                append( sb, "", 0 );
095
096                append( sb, "goal", 2 );
097                append( sb, "The name of the goal for which to show help. If unspecified, all goals will be displayed.", 3 );
098                append( sb, "Expression: ${goal}", 3 );
099                append( sb, "", 0 );
100
101                append( sb, "indentSize (Default: 2)", 2 );
102                append( sb, "The number of spaces per indentation level, should be positive.", 3 );
103                append( sb, "Expression: ${indentSize}", 3 );
104                append( sb, "", 0 );
105
106                append( sb, "lineLength (Default: 80)", 2 );
107                append( sb, "The maximum length of a display line, should be positive.", 3 );
108                append( sb, "Expression: ${lineLength}", 3 );
109                append( sb, "", 0 );
110            }
111        }
112
113        if ( goal == null || goal.length() <= 0 || "run".equals( goal ) )
114        {
115            append( sb, "andromda-bootstrap:run", 0 );
116            append( sb, "This is exactly the same as the regular AndroMDAMojo in the andromda-maven-plugin, however this is the bootstrap plugin which is used to run AndroMDA in bootstrap mode (with the bootstrap artifacts).", 1 );
117            append( sb, "", 0 );
118            if ( detail )
119            {
120                append( sb, "Available parameters:", 1 );
121                append( sb, "", 0 );
122
123                append( sb, "buildSourceDirectory", 2 );
124                append( sb, "The directory to which the build source is located (any generated source).", 3 );
125                append( sb, "Expression: ${project.build.directory}/src/main/java", 3 );
126                append( sb, "", 0 );
127
128                append( sb, "configurationUri", 2 );
129                append( sb, "This is the URI to the AndroMDA configuration file.", 3 );
130                append( sb, "Required: Yes", 3 );
131                append( sb, "Expression: file:${basedir}/conf/andromda.xml", 3 );
132                append( sb, "", 0 );
133
134                append( sb, "lastModifiedCheck", 2 );
135                append( sb, "Whether or not a last modified check should be performed before running AndroMDA again.", 3 );
136                append( sb, "Required: Yes", 3 );
137                append( sb, "Expression: false", 3 );
138                append( sb, "", 0 );
139
140                append( sb, "modelOutputHistory", 2 );
141                append( sb, "The directory where the model generation output history is located (Modelname file containing a list of files generated by that model).", 3 );
142                append( sb, "Expression: ${project.build.directory}/history", 3 );
143                append( sb, "", 0 );
144
145                append( sb, "propertyFiles", 2 );
146                append( sb, "(no description available)", 3 );
147                append( sb, "Expression: ${project.build.filters}", 3 );
148                append( sb, "", 0 );
149            }
150        }
151
152        if ( goal == null || goal.length() <= 0 || "test-translation-library".equals( goal ) )
153        {
154            append( sb, "andromda-bootstrap:test-translation-library", 0 );
155            append( sb, "The bootstrap version of the translation-library test.", 1 );
156            append( sb, "", 0 );
157            if ( detail )
158            {
159                append( sb, "Available parameters:", 1 );
160                append( sb, "", 0 );
161
162                append( sb, "configurationUri", 2 );
163                append( sb, "This is the URI to the AndroMDA configuration file.", 3 );
164                append( sb, "Required: Yes", 3 );
165                append( sb, "Expression: file:${basedir}/conf/test/andromda.xml", 3 );
166                append( sb, "", 0 );
167
168                append( sb, "propertyFiles", 2 );
169                append( sb, "(no description available)", 3 );
170                append( sb, "Expression: ${project.build.filters}", 3 );
171                append( sb, "", 0 );
172
173                append( sb, "reportDirectory", 2 );
174                append( sb, "Base directory to which the cartridge test report is written", 3 );
175                append( sb, "Expression: ${project.build.directory}/translation-library-test/reports", 3 );
176                append( sb, "", 0 );
177
178                append( sb, "skip", 2 );
179                append( sb, "Set this to \'true\' to bypass cartridge tests entirely. Its use is NOT RECOMMENDED, but quite convenient on occasion.", 3 );
180                append( sb, "Expression: ${maven.test.skip}", 3 );
181                append( sb, "", 0 );
182
183                append( sb, "skipTests", 2 );
184                append( sb, "Set this to \'true\' to skip running tests, but still compile them. Its use is NOT RECOMMENDED, but quite convenient on occasion.", 3 );
185                append( sb, "Expression: ${skipTests}", 3 );
186                append( sb, "", 0 );
187
188                append( sb, "testFailureIgnore (Default: false)", 2 );
189                append( sb, "Set this to true to ignore a failure during testing. Its use is NOT RECOMMENDED, but quite convenient on occasion.", 3 );
190                append( sb, "Expression: ${maven.test.failure.ignore}", 3 );
191                append( sb, "", 0 );
192
193                append( sb, "traceExpression", 2 );
194                append( sb, "Whether or not the expression shall be \'traced\' (i.e. the TraceTranslator will run instead of the specified translator). This is helpful, in allowing us to see which expressions are being parsed in what order, etc.", 3 );
195                append( sb, "Expression: ${trace.expression}", 3 );
196                append( sb, "", 0 );
197
198                append( sb, "translationName", 2 );
199                append( sb, "When specified, only this translation will be tested (If more than one TestTranslation-* file is found).", 3 );
200                append( sb, "Expression: ${translation.name}", 3 );
201                append( sb, "", 0 );
202            }
203        }
204
205        if ( getLog().isInfoEnabled() )
206        {
207            getLog().info( sb.toString() );
208        }
209    }
210
211    /**
212     * <p>Repeat a String <code>n</code> times to form a new string.</p>
213     *
214     * @param str String to repeat
215     * @param repeat number of times to repeat str
216     * @return String with repeated String
217     * @throws NegativeArraySizeException if <code>repeat < 0</code>
218     * @throws NullPointerException if str is <code>null</code>
219     */
220    private static String repeat( String str, int repeat )
221    {
222        StringBuffer buffer = new StringBuffer( repeat * str.length() );
223
224        for ( int i = 0; i < repeat; i++ )
225        {
226            buffer.append( str );
227        }
228
229        return buffer.toString();
230    }
231
232    /** 
233     * Append a description to the buffer by respecting the indentSize and lineLength parameters.
234     * <b>Note</b>: The last character is always a new line.
235     * 
236     * @param sb The buffer to append the description, not <code>null</code>.
237     * @param description The description, not <code>null</code>.
238     * @param indent The base indentation level of each line, must not be negative.
239     */
240    private void append( StringBuffer sb, String description, int indent )
241    {
242        for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); )
243        {
244            sb.append( it.next().toString() ).append( '\n' );
245        }
246    }
247
248    /** 
249     * Splits the specified text into lines of convenient display length.
250     * 
251     * @param text The text to split into lines, must not be <code>null</code>.
252     * @param indent The base indentation level of each line, must not be negative.
253     * @param indentSize The size of each indentation, must not be negative.
254     * @param lineLength The length of the line, must not be negative.
255     * @return The sequence of display lines, never <code>null</code>.
256     * @throws NegativeArraySizeException if <code>indent < 0</code>
257     */
258    private static List toLines( String text, int indent, int indentSize, int lineLength )
259    {
260        List lines = new ArrayList();
261
262        String ind = repeat( "\t", indent );
263        String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
264        for ( int i = 0; i < plainLines.length; i++ )
265        {
266            toLines( lines, ind + plainLines[i], indentSize, lineLength );
267        }
268
269        return lines;
270    }
271
272    /** 
273     * Adds the specified line to the output sequence, performing line wrapping if necessary.
274     * 
275     * @param lines The sequence of display lines, must not be <code>null</code>.
276     * @param line The line to add, must not be <code>null</code>.
277     * @param indentSize The size of each indentation, must not be negative.
278     * @param lineLength The length of the line, must not be negative.
279     */
280    private static void toLines( List lines, String line, int indentSize, int lineLength )
281    {
282        int lineIndent = getIndentLevel( line );
283        StringBuffer buf = new StringBuffer( 256 );
284        String[] tokens = line.split( " +" );
285        for ( int i = 0; i < tokens.length; i++ )
286        {
287            String token = tokens[i];
288            if ( i > 0 )
289            {
290                if ( buf.length() + token.length() >= lineLength )
291                {
292                    lines.add( buf.toString() );
293                    buf.setLength( 0 );
294                    buf.append( repeat( " ", lineIndent * indentSize ) );
295                }
296                else
297                {
298                    buf.append( ' ' );
299                }
300            }
301            for ( int j = 0; j < token.length(); j++ )
302            {
303                char c = token.charAt( j );
304                if ( c == '\t' )
305                {
306                    buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
307                }
308                else if ( c == '\u00A0' )
309                {
310                    buf.append( ' ' );
311                }
312                else
313                {
314                    buf.append( c );
315                }
316            }
317        }
318        lines.add( buf.toString() );
319    }
320
321    /** 
322     * Gets the indentation level of the specified line.
323     * 
324     * @param line The line whose indentation level should be retrieved, must not be <code>null</code>.
325     * @return The indentation level of the line.
326     */
327    private static int getIndentLevel( String line )
328    {
329        int level = 0;
330        for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
331        {
332            level++;
333        }
334        for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
335        {
336            if ( line.charAt( i ) == '\t' )
337            {
338                level++;
339                break;
340            }
341        }
342        return level;
343    }
344}