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