View Javadoc

1   package org.apache.maven.cli;
2   
3   import org.apache.commons.cli.CommandLine;
4   import org.apache.commons.cli.CommandLineParser;
5   import org.apache.commons.cli.GnuParser;
6   import org.apache.commons.cli.HelpFormatter;
7   import org.apache.commons.cli.OptionBuilder;
8   import org.apache.commons.cli.Options;
9   import org.apache.commons.cli.ParseException;
10  
11  import java.util.ArrayList;
12  import java.util.List;
13  
14  public class CLIManager
15  {
16  
17      public static final char ALTERNATE_POM_FILE = 'f';
18  
19      public static final char BATCH_MODE = 'B';
20  
21      public static final char SET_SYSTEM_PROPERTY = 'D';
22  
23      public static final char OFFLINE = 'o';
24  
25      public static final char REACTOR = 'r';
26  
27      public static final char QUIET = 'q';
28  
29      public static final char DEBUG = 'X';
30  
31      public static final char ERRORS = 'e';
32  
33      public static final char HELP = 'h';
34  
35      public static final char VERSION = 'v';
36  
37      public static final char SHOW_VERSION = 'V';
38  
39      private Options options;
40  
41      public static final char NON_RECURSIVE = 'N';
42  
43      public static final char UPDATE_SNAPSHOTS = 'U';
44  
45      public static final char ACTIVATE_PROFILES = 'P';
46  
47      public static final String FORCE_PLUGIN_UPDATES = "cpu";
48  
49      public static final String FORCE_PLUGIN_UPDATES2 = "up";
50  
51      public static final String SUPPRESS_PLUGIN_UPDATES = "npu";
52  
53      public static final String SUPPRESS_PLUGIN_REGISTRY = "npr";
54  
55      public static final char CHECKSUM_FAILURE_POLICY = 'C';
56  
57      public static final char CHECKSUM_WARNING_POLICY = 'c';
58  
59      public static final char ALTERNATE_USER_SETTINGS = 's';
60  
61      public static final String FAIL_FAST = "ff";
62  
63      public static final String FAIL_AT_END = "fae";
64  
65      public static final String FAIL_NEVER = "fn";
66  
67      public CLIManager()
68      {
69          options = new Options();
70  
71          options.addOption( OptionBuilder.withLongOpt( "file" )
72                                          .hasArg()
73                                          .withDescription( "Force the use of an alternate POM file." )
74                                          .create( ALTERNATE_POM_FILE ) );
75  
76          options.addOption( OptionBuilder.withLongOpt( "define" )
77                                          .hasArg()
78                                          .withDescription( "Define a system property" )
79                                          .create( SET_SYSTEM_PROPERTY ) );
80  
81          options.addOption( OptionBuilder.withLongOpt( "offline" ).withDescription( "Work offline" ).create( OFFLINE ) );
82  
83          options.addOption( OptionBuilder.withLongOpt( "help" )
84                                          .withDescription( "Display help information" )
85                                          .create( HELP ) );
86  
87          options.addOption( OptionBuilder.withLongOpt( "version" )
88                                          .withDescription( "Display version information" )
89                                          .create( VERSION ) );
90  
91          options.addOption( OptionBuilder.withLongOpt( "quiet" )
92                                          .withDescription( "Quiet output - only show errors" )
93                                          .create( QUIET ) );
94  
95          options.addOption( OptionBuilder.withLongOpt( "debug" )
96                                          .withDescription( "Produce execution debug output" )
97                                          .create( DEBUG ) );
98  
99          options.addOption( OptionBuilder.withLongOpt( "errors" )
100                                         .withDescription( "Produce execution error messages" )
101                                         .create( ERRORS ) );
102 
103         options.addOption( OptionBuilder.withLongOpt( "reactor" )
104                                         .withDescription( "Dynamically build reactor from subdirectories" )
105                                         .create( REACTOR ) );
106 
107         options.addOption( OptionBuilder.withLongOpt( "non-recursive" )
108                                         .withDescription( "Do not recurse into sub-projects" )
109                                         .create( NON_RECURSIVE ) );
110 
111         options.addOption( OptionBuilder.withLongOpt( "update-snapshots" )
112                                         .withDescription(
113                                                           "Forces a check for updated releases and snapshots on remote repositories" )
114                                         .create( UPDATE_SNAPSHOTS ) );
115 
116         options.addOption( OptionBuilder.withLongOpt( "activate-profiles" )
117                                         .withDescription( "Comma-delimited list of profiles to activate" )
118                                         .hasArg()
119                                         .create( ACTIVATE_PROFILES ) );
120 
121         options.addOption( OptionBuilder.withLongOpt( "batch-mode" )
122                                         .withDescription( "Run in non-interactive (batch) mode" )
123                                         .create( BATCH_MODE ) );
124 
125         options.addOption( OptionBuilder.withLongOpt( "check-plugin-updates" )
126                                         .withDescription( "Force upToDate check for any relevant registered plugins" )
127                                         .create( FORCE_PLUGIN_UPDATES ) );
128 
129         options.addOption( OptionBuilder.withLongOpt( "update-plugins" )
130                                         .withDescription( "Synonym for " + FORCE_PLUGIN_UPDATES )
131                                         .create( FORCE_PLUGIN_UPDATES2 ) );
132 
133         options.addOption( OptionBuilder.withLongOpt( "no-plugin-updates" )
134                                         .withDescription( "Suppress upToDate check for any relevant registered plugins" )
135                                         .create( SUPPRESS_PLUGIN_UPDATES ) );
136 
137         options.addOption( OptionBuilder.withLongOpt( "no-plugin-registry" )
138                                         .withDescription( "Don't use ~/.m2/plugin-registry.xml for plugin versions" )
139                                         .create( SUPPRESS_PLUGIN_REGISTRY ) );
140 
141         options.addOption( OptionBuilder.withLongOpt( "strict-checksums" )
142                                         .withDescription( "Fail the build if checksums don't match" )
143                                         .create( CHECKSUM_FAILURE_POLICY ) );
144 
145         options.addOption( OptionBuilder.withLongOpt( "lax-checksums" )
146                                         .withDescription( "Warn if checksums don't match" )
147                                         .create( CHECKSUM_WARNING_POLICY ) );
148 
149         options.addOption( OptionBuilder.withLongOpt( "settings" )
150                                         .withDescription( "Alternate path for the user settings file" )
151                                         .hasArg()
152                                         .create( ALTERNATE_USER_SETTINGS ) );
153 
154         options.addOption( OptionBuilder.withLongOpt( "fail-fast" )
155                                         .withDescription( "Stop at first failure in reactorized builds" )
156                                         .create( FAIL_FAST ) );
157 
158         options.addOption( OptionBuilder.withLongOpt( "fail-at-end" )
159                                         .withDescription(
160                                                           "Only fail the build afterwards; allow all non-impacted builds to continue" )
161                                         .create( FAIL_AT_END ) );
162 
163         options.addOption( OptionBuilder.withLongOpt( "fail-never" )
164                                         .withDescription( "NEVER fail the build, regardless of project result" )
165                                         .create( FAIL_NEVER ) );
166 
167         options.addOption( OptionBuilder.withLongOpt( "show-version" )
168                                         .withDescription( "Display version information WITHOUT stopping build" )
169                                         .create( SHOW_VERSION ) );
170     }
171 
172     public CommandLine parse( String[] args )
173         throws ParseException
174     {
175         // We need to eat any quotes surrounding arguments...
176         String[] cleanArgs = cleanArgs( args );
177 
178         CommandLineParser parser = new GnuParser();
179         return parser.parse( options, cleanArgs );
180     }
181 
182     private String[] cleanArgs( String[] args )
183     {
184         List cleaned = new ArrayList();
185 
186         StringBuffer currentArg = null;
187 
188         for ( int i = 0; i < args.length; i++ )
189         {
190             String arg = args[i];
191 
192 //            System.out.println( "Processing raw arg: " + arg );
193 
194             boolean addedToBuffer = false;
195 
196             if ( arg.startsWith( "\"" ) )
197             {
198                 // if we're in the process of building up another arg, push it and start over.
199                 // this is for the case: "-Dfoo=bar "-Dfoo2=bar two" (note the first unterminated quote)
200                 if ( currentArg != null )
201                 {
202 //                    System.out.println( "Flushing last arg buffer: \'" + currentArg + "\' to cleaned list." );
203                     cleaned.add( currentArg.toString() );
204                 }
205 
206                 // start building an argument here.
207                 currentArg = new StringBuffer( arg.substring( 1 ) );
208                 addedToBuffer = true;
209             }
210 
211             // this has to be a separate "if" statement, to capture the case of: "-Dfoo=bar"
212             if ( arg.endsWith( "\"" ) )
213             {
214                 String cleanArgPart = arg.substring( 0, arg.length() - 1 );
215 
216                 // if we're building an argument, keep doing so.
217                 if ( currentArg != null )
218                 {
219                     // if this is the case of "-Dfoo=bar", then we need to adjust the buffer.
220                     if ( addedToBuffer )
221                     {
222 //                        System.out.println( "Adjusting argument already appended to the arg buffer." );
223                         currentArg.setLength( currentArg.length() - 1 );
224                     }
225                     // otherwise, we trim the trailing " and append to the buffer.
226                     else
227                     {
228 //                        System.out.println( "Appending arg part: \'" + cleanArgPart + "\' with preceding space to arg buffer." );
229                         // TODO: introducing a space here...not sure what else to do but collapse whitespace
230                         currentArg.append( ' ' ).append( cleanArgPart );
231                     }
232 
233 //                    System.out.println( "Flushing completed arg buffer: \'" + currentArg + "\' to cleaned list." );
234 
235                     // we're done with this argument, so add it.
236                     cleaned.add( currentArg.toString() );
237                 }
238                 else
239                 {
240 //                    System.out.println( "appending cleaned arg: \'" + cleanArgPart + "\' directly to cleaned list." );
241                     // this is a simple argument...just add it.
242                     cleaned.add( cleanArgPart );
243                 }
244 
245 //                System.out.println( "Clearing arg buffer." );
246                 // the currentArg MUST be finished when this completes.
247                 currentArg = null;
248                 continue;
249             }
250 
251             // if we haven't added this arg to the buffer, and we ARE building an argument
252             // buffer, then append it with a preceding space...again, not sure what else to
253             // do other than collapse whitespace.
254             // NOTE: The case of a trailing quote is handled by nullifying the arg buffer.
255             if ( !addedToBuffer )
256             {
257                 // append to the argument we're building, collapsing whitespace to a single space.
258                 if ( currentArg != null )
259                 {
260 //                    System.out.println( "Append unquoted arg part: \'" + arg + "\' to arg buffer." );
261                     currentArg.append( ' ' ).append( arg );
262                 }
263                 // this is a loner, just add it directly.
264                 else
265                 {
266 //                    System.out.println( "Append unquoted arg part: \'" + arg + "\' directly to cleaned list." );
267                     cleaned.add( arg );
268                 }
269             }
270         }
271 
272         // clean up.
273         if ( currentArg != null )
274         {
275 //            System.out.println( "Adding unterminated arg buffer: \'" + currentArg + "\' to cleaned list." );
276             cleaned.add( currentArg.toString() );
277         }
278 
279         int cleanedSz = cleaned.size();
280         String[] cleanArgs = null;
281 
282         if ( cleanedSz == 0 )
283         {
284             // if we didn't have any arguments to clean, simply pass the original array through
285             cleanArgs = args;
286         }
287         else
288         {
289 //            System.out.println( "Cleaned argument list:\n" + cleaned );
290             cleanArgs = (String[]) cleaned.toArray( new String[cleanedSz] );
291         }
292 
293         return cleanArgs;
294     }
295 
296     public void displayHelp()
297     {
298         System.out.println();
299 
300         HelpFormatter formatter = new HelpFormatter();
301         formatter.printHelp( "mvn [options] [<goal(s)>] [<phase(s)>]", "\nOptions:", options, "\n" );
302     }
303     
304 }