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 ALTERNATE_GLOBAL_SETTINGS = "gs";
62  
63      public static final String FAIL_FAST = "ff";
64  
65      public static final String FAIL_AT_END = "fae";
66  
67      public static final String FAIL_NEVER = "fn";
68      
69      public static final String RESUME_FROM = "rf";
70      
71      public static final String PROJECT_LIST = "pl";
72      
73      public static final String ALSO_MAKE = "am";
74      
75      public static final String ALSO_MAKE_DEPENDENTS = "amd";
76  
77      public static final String ENCRYPT_MASTER_PASSWORD = "emp";
78  
79      public static final String ENCRYPT_PASSWORD = "ep";
80  
81      public CLIManager()
82      {
83          options = new Options();
84  
85          options.addOption( OptionBuilder.withLongOpt( "file" )
86                                          .hasArg()
87                                          .withDescription( "Force the use of an alternate POM file." )
88                                          .create( ALTERNATE_POM_FILE ) );
89  
90          options.addOption( OptionBuilder.withLongOpt( "define" )
91                                          .hasArg()
92                                          .withDescription( "Define a system property" )
93                                          .create( SET_SYSTEM_PROPERTY ) );
94  
95          options.addOption( OptionBuilder.withLongOpt( "offline" ).withDescription( "Work offline" ).create( OFFLINE ) );
96  
97          options.addOption( OptionBuilder.withLongOpt( "help" )
98                                          .withDescription( "Display help information" )
99                                          .create( HELP ) );
100 
101         options.addOption( OptionBuilder.withLongOpt( "version" )
102                                         .withDescription( "Display version information" )
103                                         .create( VERSION ) );
104 
105         options.addOption( OptionBuilder.withLongOpt( "encrypt-master-password" )
106                            .hasArg()
107                            .withDescription( "Encrypt master security password" )
108                            .create( ENCRYPT_MASTER_PASSWORD ) );
109         options.addOption( OptionBuilder.withLongOpt( "encrypt-password" )
110                            .hasArg()
111                            .withDescription( "Encrypt server password" )
112                            .create( ENCRYPT_PASSWORD ) );
113 
114         options.addOption( OptionBuilder.withLongOpt( "quiet" )
115                                         .withDescription( "Quiet output - only show errors" )
116                                         .create( QUIET ) );
117 
118         options.addOption( OptionBuilder.withLongOpt( "debug" )
119                                         .withDescription( "Produce execution debug output" )
120                                         .create( DEBUG ) );
121 
122         options.addOption( OptionBuilder.withLongOpt( "errors" )
123                                         .withDescription( "Produce execution error messages" )
124                                         .create( ERRORS ) );
125 
126         options.addOption( OptionBuilder.withLongOpt( "reactor" )
127                                         .withDescription( "Dynamically build reactor from subdirectories" )
128                                         .create( REACTOR ) );
129 
130         options.addOption( OptionBuilder.withLongOpt( "non-recursive" )
131                                         .withDescription( "Do not recurse into sub-projects" )
132                                         .create( NON_RECURSIVE ) );
133 
134         options.addOption( OptionBuilder.withLongOpt( "update-snapshots" )
135                                         .withDescription(
136                                                           "Forces a check for updated releases and snapshots on remote repositories" )
137                                         .create( UPDATE_SNAPSHOTS ) );
138 
139         options.addOption( OptionBuilder.withLongOpt( "activate-profiles" )
140                                         .withDescription( "Comma-delimited list of profiles to activate" )
141                                         .hasArg()
142                                         .create( ACTIVATE_PROFILES ) );
143 
144         options.addOption( OptionBuilder.withLongOpt( "batch-mode" )
145                                         .withDescription( "Run in non-interactive (batch) mode" )
146                                         .create( BATCH_MODE ) );
147 
148         options.addOption( OptionBuilder.withLongOpt( "check-plugin-updates" )
149                                         .withDescription( "Force upToDate check for any relevant registered plugins" )
150                                         .create( FORCE_PLUGIN_UPDATES ) );
151 
152         options.addOption( OptionBuilder.withLongOpt( "update-plugins" )
153                                         .withDescription( "Synonym for " + FORCE_PLUGIN_UPDATES )
154                                         .create( FORCE_PLUGIN_UPDATES2 ) );
155 
156         options.addOption( OptionBuilder.withLongOpt( "no-plugin-updates" )
157                                         .withDescription( "Suppress upToDate check for any relevant registered plugins" )
158                                         .create( SUPPRESS_PLUGIN_UPDATES ) );
159 
160         options.addOption( OptionBuilder.withLongOpt( "no-plugin-registry" )
161                                         .withDescription( "Don't use ~/.m2/plugin-registry.xml for plugin versions" )
162                                         .create( SUPPRESS_PLUGIN_REGISTRY ) );
163 
164         options.addOption( OptionBuilder.withLongOpt( "strict-checksums" )
165                                         .withDescription( "Fail the build if checksums don't match" )
166                                         .create( CHECKSUM_FAILURE_POLICY ) );
167 
168         options.addOption( OptionBuilder.withLongOpt( "lax-checksums" )
169                                         .withDescription( "Warn if checksums don't match" )
170                                         .create( CHECKSUM_WARNING_POLICY ) );
171 
172         options.addOption( OptionBuilder.withLongOpt( "settings" )
173                                         .withDescription( "Alternate path for the user settings file" )
174                                         .hasArg()
175                                         .create( ALTERNATE_USER_SETTINGS ) );
176 
177         options.addOption( OptionBuilder.withLongOpt( "global-settings" )
178                                         .withDescription( "Alternate path for the global settings file" )
179                                         .hasArg()
180                                         .create( ALTERNATE_GLOBAL_SETTINGS ) );
181 
182         options.addOption( OptionBuilder.withLongOpt( "fail-fast" )
183                                         .withDescription( "Stop at first failure in reactorized builds" )
184                                         .create( FAIL_FAST ) );
185 
186         options.addOption( OptionBuilder.withLongOpt( "fail-at-end" )
187                                         .withDescription(
188                                                           "Only fail the build afterwards; allow all non-impacted builds to continue" )
189                                         .create( FAIL_AT_END ) );
190 
191         options.addOption( OptionBuilder.withLongOpt( "fail-never" )
192                                         .withDescription( "NEVER fail the build, regardless of project result" )
193                                         .create( FAIL_NEVER ) );
194 
195         options.addOption( OptionBuilder.withLongOpt( "show-version" )
196                                         .withDescription( "Display version information WITHOUT stopping build" )
197                                         .create( SHOW_VERSION ) );
198 
199         options.addOption( OptionBuilder.withLongOpt( "resume-from" )
200                                         .hasArg()
201                                         .withDescription( "Resume reactor from specified project" )
202                                         .create( RESUME_FROM ) );
203 
204         options.addOption( OptionBuilder.withLongOpt( "projects" )
205                                         .withDescription( "Build specified reactor projects instead of all projects" )
206                                         .hasArg()
207                                         .create( PROJECT_LIST ) );
208 
209         options.addOption( OptionBuilder.withLongOpt( "also-make" )
210                                         .withDescription(
211                                                           "If project list is specified, also build projects required by the list" )
212                                         .create( ALSO_MAKE ) );
213 
214         options.addOption( OptionBuilder.withLongOpt( "also-make-dependents" )
215                                         .withDescription(
216                                                           "If project list is specified, also build projects that depend on projects on the list" )
217                                         .create( ALSO_MAKE_DEPENDENTS ) );
218     }
219 
220     public CommandLine parse( String[] args )
221         throws ParseException
222     {
223         // We need to eat any quotes surrounding arguments...
224         String[] cleanArgs = cleanArgs( args );
225 
226         CommandLineParser parser = new GnuParser();
227         return parser.parse( options, cleanArgs );
228     }
229 
230     private String[] cleanArgs( String[] args )
231     {
232         List cleaned = new ArrayList();
233 
234         StringBuffer currentArg = null;
235 
236         for ( int i = 0; i < args.length; i++ )
237         {
238             String arg = args[i];
239 
240 //            System.out.println( "Processing raw arg: " + arg );
241 
242             boolean addedToBuffer = false;
243 
244             if ( arg.startsWith( "\"" ) )
245             {
246                 // if we're in the process of building up another arg, push it and start over.
247                 // this is for the case: "-Dfoo=bar "-Dfoo2=bar two" (note the first unterminated quote)
248                 if ( currentArg != null )
249                 {
250 //                    System.out.println( "Flushing last arg buffer: \'" + currentArg + "\' to cleaned list." );
251                     cleaned.add( currentArg.toString() );
252                 }
253 
254                 // start building an argument here.
255                 currentArg = new StringBuffer( arg.substring( 1 ) );
256                 addedToBuffer = true;
257             }
258 
259             // this has to be a separate "if" statement, to capture the case of: "-Dfoo=bar"
260             if ( arg.endsWith( "\"" ) )
261             {
262                 String cleanArgPart = arg.substring( 0, arg.length() - 1 );
263 
264                 // if we're building an argument, keep doing so.
265                 if ( currentArg != null )
266                 {
267                     // if this is the case of "-Dfoo=bar", then we need to adjust the buffer.
268                     if ( addedToBuffer )
269                     {
270 //                        System.out.println( "Adjusting argument already appended to the arg buffer." );
271                         currentArg.setLength( currentArg.length() - 1 );
272                     }
273                     // otherwise, we trim the trailing " and append to the buffer.
274                     else
275                     {
276 //                        System.out.println( "Appending arg part: \'" + cleanArgPart + "\' with preceding space to arg buffer." );
277                         // TODO: introducing a space here...not sure what else to do but collapse whitespace
278                         currentArg.append( ' ' ).append( cleanArgPart );
279                     }
280 
281 //                    System.out.println( "Flushing completed arg buffer: \'" + currentArg + "\' to cleaned list." );
282 
283                     // we're done with this argument, so add it.
284                     cleaned.add( currentArg.toString() );
285                 }
286                 else
287                 {
288 //                    System.out.println( "appending cleaned arg: \'" + cleanArgPart + "\' directly to cleaned list." );
289                     // this is a simple argument...just add it.
290                     cleaned.add( cleanArgPart );
291                 }
292 
293 //                System.out.println( "Clearing arg buffer." );
294                 // the currentArg MUST be finished when this completes.
295                 currentArg = null;
296                 continue;
297             }
298 
299             // if we haven't added this arg to the buffer, and we ARE building an argument
300             // buffer, then append it with a preceding space...again, not sure what else to
301             // do other than collapse whitespace.
302             // NOTE: The case of a trailing quote is handled by nullifying the arg buffer.
303             if ( !addedToBuffer )
304             {
305                 // append to the argument we're building, collapsing whitespace to a single space.
306                 if ( currentArg != null )
307                 {
308 //                    System.out.println( "Append unquoted arg part: \'" + arg + "\' to arg buffer." );
309                     currentArg.append( ' ' ).append( arg );
310                 }
311                 // this is a loner, just add it directly.
312                 else
313                 {
314 //                    System.out.println( "Append unquoted arg part: \'" + arg + "\' directly to cleaned list." );
315                     cleaned.add( arg );
316                 }
317             }
318         }
319 
320         // clean up.
321         if ( currentArg != null )
322         {
323 //            System.out.println( "Adding unterminated arg buffer: \'" + currentArg + "\' to cleaned list." );
324             cleaned.add( currentArg.toString() );
325         }
326 
327         int cleanedSz = cleaned.size();
328         String[] cleanArgs = null;
329 
330         if ( cleanedSz == 0 )
331         {
332             // if we didn't have any arguments to clean, simply pass the original array through
333             cleanArgs = args;
334         }
335         else
336         {
337 //            System.out.println( "Cleaned argument list:\n" + cleaned );
338             cleanArgs = (String[]) cleaned.toArray( new String[cleanedSz] );
339         }
340 
341         return cleanArgs;
342     }
343 
344     public void displayHelp()
345     {
346         System.out.println();
347 
348         HelpFormatter formatter = new HelpFormatter();
349         formatter.printHelp( "mvn [options] [<goal(s)>] [<phase(s)>]", "\nOptions:", options, "\n" );
350     }
351     
352 }