Coverage Report - org.codehaus.plexus.tools.cli.AbstractCli
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractCli
36 %
50/136
32 %
19/58
3,533
 
 1  
 package org.codehaus.plexus.tools.cli;
 2  
 
 3  
 /*
 4  
  * Copyright 2006 The Codehaus Foundation.
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *      http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 19  
 import org.apache.commons.cli.CommandLine;
 20  
 import org.apache.commons.cli.CommandLineParser;
 21  
 import org.apache.commons.cli.GnuParser;
 22  
 import org.apache.commons.cli.HelpFormatter;
 23  
 import org.apache.commons.cli.OptionBuilder;
 24  
 import org.apache.commons.cli.Options;
 25  
 import org.apache.commons.cli.ParseException;
 26  
 import org.codehaus.plexus.ContainerConfiguration;
 27  
 import org.codehaus.plexus.DefaultContainerConfiguration;
 28  
 import org.codehaus.plexus.DefaultPlexusContainer;
 29  
 import org.codehaus.plexus.PlexusContainer;
 30  
 import org.codehaus.plexus.PlexusContainerException;
 31  
 import org.codehaus.plexus.classworlds.ClassWorld;
 32  
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 33  
 
 34  
 import java.io.IOException;
 35  
 import java.io.InputStream;
 36  
 import java.util.ArrayList;
 37  
 import java.util.List;
 38  
 import java.util.Properties;
 39  
 
 40  
 /**
 41  
  * @author jason van zyl
 42  
  * @version $Id$
 43  
  * @noinspection UseOfSystemOutOrSystemErr,ACCESS_STATIC_VIA_INSTANCE
 44  
  */
 45  1
 public abstract class AbstractCli
 46  
     implements Cli
 47  
 {
 48  
     // ----------------------------------------------------------------------------
 49  
     // These are standard options that we would want to use for all our projects.
 50  
     // ----------------------------------------------------------------------------
 51  
 
 52  
     public static final char QUIET = 'q';
 53  
 
 54  
     public static final char DEBUG = 'X';
 55  
 
 56  
     public static final char ERRORS = 'e';
 57  
 
 58  
     public static final char HELP = 'h';
 59  
 
 60  
     public static final char VERSION = 'v';
 61  
 
 62  
     public static final char SET_SYSTEM_PROPERTY = 'D';
 63  
 
 64  
     // ----------------------------------------------------------------------------
 65  
     // Abstract methods
 66  
     // ----------------------------------------------------------------------------
 67  
 
 68  
     public abstract Options buildCliOptions( Options options );
 69  
 
 70  
     public abstract void invokePlexusComponent( CommandLine cli,
 71  
                                                 PlexusContainer container )
 72  
         throws Exception;
 73  
 
 74  
     public String getPomPropertiesPath()
 75  
     {
 76  0
         return null;
 77  
     }
 78  
 
 79  
     public int execute( String[] args )
 80  
     {
 81  1
         ClassWorld classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
 82  
 
 83  1
         return execute( args, classWorld );
 84  
     }
 85  
 
 86  
     public int execute( String[] args,
 87  
                         ClassWorld classWorld )
 88  
     {
 89  
         CommandLine cli;
 90  
 
 91  
         try
 92  
         {
 93  1
             cli = parse( args );
 94  
         }
 95  0
         catch ( ParseException e )
 96  
         {
 97  0
             System.err.println( "Unable to parse command line options: " + e.getMessage() );
 98  
 
 99  0
             displayHelp();
 100  
 
 101  0
             return 1;
 102  1
         }
 103  
 
 104  1
         if ( System.getProperty( "java.class.version", "44.0" ).compareTo( "48.0" ) < 0 )
 105  
         {
 106  0
             System.err.println( "Sorry, but JDK 1.4 or above is required to execute Maven" );
 107  
 
 108  0
             System.err.println(
 109  
                 "You appear to be using Java version: " + System.getProperty( "java.version", "<unknown>" ) );
 110  
 
 111  0
             return 1;
 112  
         }
 113  
 
 114  1
         boolean debug = cli.hasOption( DEBUG );
 115  
 
 116  1
         boolean quiet = !debug && cli.hasOption( QUIET );
 117  
 
 118  1
         boolean showErrors = debug || cli.hasOption( ERRORS );
 119  
 
 120  1
         if ( showErrors )
 121  
         {
 122  0
             System.out.println( "+ Error stacktraces are turned on." );
 123  
         }
 124  
 
 125  
         // ----------------------------------------------------------------------------
 126  
         // Logging
 127  
         // ----------------------------------------------------------------------------
 128  
 
 129  
         int loggingLevel;
 130  
 
 131  1
         if ( debug )
 132  
         {
 133  0
             loggingLevel = 0;
 134  
         }
 135  1
         else if ( quiet )
 136  
         {
 137  0
             loggingLevel = 0;
 138  
         }
 139  
         else
 140  
         {
 141  1
             loggingLevel = 0;
 142  
         }
 143  
 
 144  
         // ----------------------------------------------------------------------
 145  
         // Process particular command line options
 146  
         // ----------------------------------------------------------------------
 147  
 
 148  1
         if ( cli.hasOption( HELP ) )
 149  
         {
 150  0
             displayHelp();
 151  
 
 152  0
             return 0;
 153  
         }
 154  
 
 155  1
         if ( cli.hasOption( VERSION ) )
 156  
         {
 157  0
             showVersion();
 158  
 
 159  0
             return 0;
 160  
         }
 161  1
         else if ( debug )
 162  
         {
 163  0
             showVersion();
 164  
         }
 165  
 
 166  
         // ----------------------------------------------------------------------------
 167  
         // This is what we will generalize for the invocation of the command line.
 168  
         // ----------------------------------------------------------------------------
 169  
 
 170  
         try
 171  
         {
 172  1
             ContainerConfiguration configuration = new DefaultContainerConfiguration()
 173  
                 .setClassWorld( classWorld );
 174  
 
 175  1
             customizeContainerConfiguration( configuration, cli );
 176  
             
 177  1
             PlexusContainer plexus = new DefaultPlexusContainer( configuration );
 178  
 
 179  1
             invokePlexusComponent( cli, plexus );
 180  
         }
 181  0
         catch ( PlexusContainerException e )
 182  
         {
 183  0
             showFatalError( "Cannot create Plexus container.", e, true );
 184  
         }
 185  0
         catch ( ComponentLookupException e )
 186  
         {
 187  0
             showError( "Cannot lookup application component.", e, true );
 188  
         }
 189  0
         catch ( Exception e )
 190  
         {
 191  0
             showError( "Problem executing command line.", e, true );
 192  1
         }
 193  
 
 194  1
         return 0;
 195  
     }
 196  
 
 197  
     protected void customizeContainerConfiguration( ContainerConfiguration configuration, CommandLine cli )
 198  
     {        
 199  1
     }
 200  
     
 201  
     protected int showFatalError( String message,
 202  
                                   Exception e,
 203  
                                   boolean show )
 204  
     {
 205  0
         System.err.println( "FATAL ERROR: " + message );
 206  
 
 207  0
         if ( show )
 208  
         {
 209  0
             System.err.println( "Error stacktrace:" );
 210  
 
 211  0
             e.printStackTrace();
 212  
         }
 213  
         else
 214  
         {
 215  0
             System.err.println( "For more information, run with the -e flag" );
 216  
         }
 217  
 
 218  0
         return 1;
 219  
     }
 220  
 
 221  
     protected void showError( String message,
 222  
                               Exception e,
 223  
                               boolean show )
 224  
     {
 225  0
         System.err.println( message );
 226  
 
 227  0
         if ( show )
 228  
         {
 229  0
             System.err.println( "Error stacktrace:" );
 230  
 
 231  0
             e.printStackTrace();
 232  
         }
 233  0
     }
 234  
 
 235  
     // Need to get the versions of the application in a general way, so that I need a way to get the
 236  
     // specifics of the application so that I can do this in a general way.
 237  
     private void showVersion()
 238  
     {
 239  
         InputStream is;
 240  
 
 241  
         try
 242  
         {
 243  0
             Properties properties = new Properties();
 244  
 
 245  0
             String pomPropertiesPath = getPomPropertiesPath();
 246  
 
 247  0
             if ( pomPropertiesPath == null )
 248  
             {
 249  0
                 System.err.println( "Unable determine version from JAR file." );
 250  
 
 251  0
                 return;
 252  
             }
 253  
 
 254  0
             is = AbstractCli.class.getClassLoader().getResourceAsStream( pomPropertiesPath );
 255  
 
 256  0
             if ( is == null )
 257  
             {
 258  0
                 System.err.println( "Unable determine version from JAR file." );
 259  
 
 260  0
                 return;
 261  
             }
 262  
 
 263  0
             properties.load( is );
 264  
 
 265  0
             if ( properties.getProperty( "builtOn" ) != null )
 266  
             {
 267  0
                 System.out.println( "Version: " + properties.getProperty( "version", "unknown" ) + " built on " +
 268  
                     properties.getProperty( "builtOn" ) );
 269  
             }
 270  
             else
 271  
             {
 272  0
                 System.out.println( "Version: " + properties.getProperty( "version", "unknown" ) );
 273  
             }
 274  
         }
 275  0
         catch ( IOException e )
 276  
         {
 277  0
             System.err.println( "Unable determine version from JAR file: " + e.getMessage() );
 278  0
         }
 279  0
     }
 280  
 
 281  
     // ----------------------------------------------------------------------
 282  
     // System properties handling
 283  
     // ----------------------------------------------------------------------
 284  
 
 285  
     private Properties getExecutionProperties( CommandLine commandLine )
 286  
     {
 287  0
         Properties executionProperties = new Properties();
 288  
 
 289  
         // ----------------------------------------------------------------------
 290  
         // Options that are set on the command line become system properties
 291  
         // and therefore are set in the session properties. System properties
 292  
         // are most dominant.
 293  
         // ----------------------------------------------------------------------
 294  
 
 295  0
         if ( commandLine.hasOption( SET_SYSTEM_PROPERTY ) )
 296  
         {
 297  0
             String[] defStrs = commandLine.getOptionValues( SET_SYSTEM_PROPERTY );
 298  
 
 299  0
             for ( int i = 0; i < defStrs.length; ++i )
 300  
             {
 301  0
                 setCliProperty( defStrs[i], executionProperties );
 302  
             }
 303  
         }
 304  
 
 305  0
         executionProperties.putAll( System.getProperties() );
 306  
 
 307  0
         return executionProperties;
 308  
     }
 309  
 
 310  
     private void setCliProperty( String property,
 311  
                                  Properties executionProperties )
 312  
     {
 313  
         String name;
 314  
 
 315  
         String value;
 316  
 
 317  0
         int i = property.indexOf( "=" );
 318  
 
 319  0
         if ( i <= 0 )
 320  
         {
 321  0
             name = property.trim();
 322  
 
 323  0
             value = "true";
 324  
         }
 325  
         else
 326  
         {
 327  0
             name = property.substring( 0, i ).trim();
 328  
 
 329  0
             value = property.substring( i + 1 ).trim();
 330  
         }
 331  
 
 332  0
         executionProperties.setProperty( name, value );
 333  
 
 334  
         // ----------------------------------------------------------------------
 335  
         // I'm leaving the setting of system properties here as not to break
 336  
         // the SystemPropertyProfileActivator. This won't harm embedding. jvz.
 337  
         // ----------------------------------------------------------------------
 338  
 
 339  0
         System.setProperty( name, value );
 340  0
     }
 341  
 
 342  
     private Options options;
 343  
 
 344  
     public Options buildDefaultCliOptions()
 345  
     {
 346  1
         options = new Options();
 347  
 
 348  1
         options.addOption(
 349  
             OptionBuilder.withLongOpt( "define" ).hasArg().withDescription( "Define a system property" ).create(
 350  
                 SET_SYSTEM_PROPERTY ) );
 351  1
         options.addOption(
 352  
             OptionBuilder.withLongOpt( "help" ).withDescription( "Display help information" ).create( HELP ) );
 353  1
         options.addOption(
 354  
             OptionBuilder.withLongOpt( "version" ).withDescription( "Display version information" ).create( VERSION ) );
 355  1
         options.addOption(
 356  
             OptionBuilder.withLongOpt( "quiet" ).withDescription( "Quiet output - only show errors" ).create( QUIET ) );
 357  1
         options.addOption(
 358  
             OptionBuilder.withLongOpt( "debug" ).withDescription( "Produce execution debug output" ).create( DEBUG ) );
 359  1
         options.addOption(
 360  
             OptionBuilder.withLongOpt( "errors" ).withDescription( "Produce execution error messages" ).create(
 361  
                 ERRORS ) );
 362  
 
 363  1
         return buildCliOptions( options );
 364  
     }
 365  
 
 366  
     public CommandLine parse( String[] args )
 367  
         throws ParseException
 368  
     {
 369  
         // We need to eat any quotes surrounding arguments...
 370  1
         String[] cleanArgs = cleanArgs( args );
 371  
 
 372  1
         CommandLineParser parser = new GnuParser();
 373  
 
 374  1
         return parser.parse( buildDefaultCliOptions(), cleanArgs );
 375  
     }
 376  
 
 377  
     private static String[] cleanArgs( String[] args )
 378  
     {
 379  1
         List cleaned = new ArrayList();
 380  
 
 381  1
         StringBuffer currentArg = null;
 382  
 
 383  3
         for ( int i = 0; i < args.length; i++ )
 384  
         {
 385  2
             String arg = args[i];
 386  
 
 387  2
             boolean addedToBuffer = false;
 388  
 
 389  2
             if ( arg.startsWith( "\"" ) )
 390  
             {
 391  
                 // if we're in the process of building up another arg, push it and start over.
 392  
                 // this is for the case: "-Dfoo=bar "-Dfoo2=bar two" (note the first unterminated quote)
 393  0
                 if ( currentArg != null )
 394  
                 {
 395  0
                     cleaned.add( currentArg.toString() );
 396  
                 }
 397  
 
 398  
                 // start building an argument here.
 399  0
                 currentArg = new StringBuffer( arg.substring( 1 ) );
 400  
 
 401  0
                 addedToBuffer = true;
 402  
             }
 403  
 
 404  
             // this has to be a separate "if" statement, to capture the case of: "-Dfoo=bar"
 405  2
             if ( arg.endsWith( "\"" ) )
 406  
             {
 407  0
                 String cleanArgPart = arg.substring( 0, arg.length() - 1 );
 408  
 
 409  
                 // if we're building an argument, keep doing so.
 410  0
                 if ( currentArg != null )
 411  
                 {
 412  
                     // if this is the case of "-Dfoo=bar", then we need to adjust the buffer.
 413  0
                     if ( addedToBuffer )
 414  
                     {
 415  0
                         currentArg.setLength( currentArg.length() - 1 );
 416  
                     }
 417  
                     // otherwise, we trim the trailing " and append to the buffer.
 418  
                     else
 419  
                     {
 420  
                         // TODO: introducing a space here...not sure what else to do but collapse whitespace
 421  0
                         currentArg.append( ' ' ).append( cleanArgPart );
 422  
                     }
 423  
 
 424  
                     // we're done with this argument, so add it.
 425  0
                     cleaned.add( currentArg.toString() );
 426  
                 }
 427  
                 else
 428  
                 {
 429  
                     // this is a simple argument...just add it.
 430  0
                     cleaned.add( cleanArgPart );
 431  
                 }
 432  
 
 433  
                 // the currentArg MUST be finished when this completes.
 434  0
                 currentArg = null;
 435  
 
 436  0
                 continue;
 437  
             }
 438  
 
 439  
             // if we haven't added this arg to the buffer, and we ARE building an argument
 440  
             // buffer, then append it with a preceding space...again, not sure what else to
 441  
             // do other than collapse whitespace.
 442  
             // NOTE: The case of a trailing quote is handled by nullifying the arg buffer.
 443  2
             if ( !addedToBuffer )
 444  
             {
 445  
                 // append to the argument we're building, collapsing whitespace to a single space.
 446  2
                 if ( currentArg != null )
 447  
                 {
 448  0
                     currentArg.append( ' ' ).append( arg );
 449  
                 }
 450  
                 // this is a loner, just add it directly.
 451  
                 else
 452  
                 {
 453  2
                     cleaned.add( arg );
 454  
                 }
 455  
             }
 456  
         }
 457  
 
 458  
         // clean up.
 459  1
         if ( currentArg != null )
 460  
         {
 461  0
             cleaned.add( currentArg.toString() );
 462  
         }
 463  
 
 464  1
         int cleanedSz = cleaned.size();
 465  1
         String[] cleanArgs = null;
 466  
 
 467  1
         if ( cleanedSz == 0 )
 468  
         {
 469  
             // if we didn't have any arguments to clean, simply pass the original array through
 470  0
             cleanArgs = args;
 471  
         }
 472  
         else
 473  
         {
 474  1
             cleanArgs = (String[]) cleaned.toArray( new String[cleanedSz] );
 475  
         }
 476  
 
 477  1
         return cleanArgs;
 478  
     }
 479  
 
 480  
     public void displayHelp()
 481  
     {
 482  0
         System.out.println();
 483  
 
 484  0
         HelpFormatter formatter = new HelpFormatter();
 485  
 
 486  0
         formatter.printHelp( "mvn [options] [<goal(s)>] [<phase(s)>]", "\nOptions:", options, "\n" );
 487  0
     }
 488  
 }