View Javadoc

1   package org.apache.maven.shared.invoker;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Properties;
28  
29  import org.codehaus.plexus.util.Os;
30  import org.codehaus.plexus.util.StringUtils;
31  import org.codehaus.plexus.util.cli.CommandLineUtils;
32  import org.codehaus.plexus.util.cli.Commandline;
33  
34  /**
35   * @version $Id: MavenCommandLineBuilder.java 807829 2009-08-25 22:06:10Z olamy $
36   */
37  public class MavenCommandLineBuilder
38  {
39  
40      private static final InvokerLogger DEFAULT_LOGGER = new SystemOutLogger();
41  
42      private InvokerLogger logger = DEFAULT_LOGGER;
43  
44      private File workingDirectory;
45  
46      private File localRepositoryDirectory;
47  
48      private File mavenHome;
49  
50      private File mvnCommand;
51  
52      private Properties systemEnvVars;
53  
54      public Commandline build( InvocationRequest request )
55          throws CommandLineConfigurationException
56      {
57          try
58          {
59              checkRequiredState();
60          }
61          catch ( IOException e )
62          {
63              throw new CommandLineConfigurationException( e.getMessage(), e );
64          }
65          File mvn = null;
66          try
67          {
68              mvn = findMavenExecutable();
69          }
70          catch ( IOException e )
71          {
72              throw new CommandLineConfigurationException( e.getMessage(), e );
73          }
74          Commandline cli = new Commandline();
75  
76          cli.setExecutable( mvn.getAbsolutePath() );
77  
78          // handling for OS-level envars
79          setShellEnvironment( request, cli );
80  
81          // interactive, offline, update-snapshots,
82          // debug/show-errors, checksum policy
83          setFlags( request, cli );
84  
85          // failure behavior and [eventually] forced-reactor
86          // includes/excludes, etc.
87          setReactorBehavior( request, cli );
88  
89          // working directory and local repository location
90          setEnvironmentPaths( request, cli );
91  
92          // pom-file and basedir handling
93          setPomLocation( request, cli );
94  
95          setSettingsLocation( request, cli );
96  
97          setProperties( request, cli );
98  
99          setProfiles( request, cli );
100 
101         setGoals( request, cli );
102 
103         return cli;
104     }
105 
106     protected void checkRequiredState()
107         throws IOException
108     {
109         if ( logger == null )
110         {
111             throw new IllegalStateException( "A logger instance is required." );
112         }
113 
114         if ( ( mavenHome == null ) && ( System.getProperty( "maven.home" ) == null ) )
115         // can be restored with 1.5
116         // && ( System.getenv( "M2_HOME" ) != null ) )
117         {
118             if ( !getSystemEnvVars().containsKey( "M2_HOME" ) )
119             {
120                 throw new IllegalStateException( "Maven application directory was not "
121                     + "specified, and ${maven.home} is not provided in the system "
122                     + "properties. Please specify at least on of these." );
123             }
124         }
125     }
126 
127     protected void setSettingsLocation( InvocationRequest request, Commandline cli )
128     {
129         File userSettingsFile = request.getUserSettingsFile();
130 
131         if ( userSettingsFile != null )
132         {
133             try
134             {
135                 File canSet = userSettingsFile.getCanonicalFile();
136                 userSettingsFile = canSet;
137             }
138             catch ( IOException e )
139             {
140                 logger.debug( "Failed to canonicalize user settings path: " + userSettingsFile.getAbsolutePath()
141                     + ". Using as-is.", e );
142             }
143 
144             cli.createArg().setValue( "-s" );
145             cli.createArg().setValue( userSettingsFile.getPath() );
146         }
147     }
148 
149     protected void setShellEnvironment( InvocationRequest request, Commandline cli )
150         throws CommandLineConfigurationException
151     {
152         if ( request.isShellEnvironmentInherited() )
153         {
154             try
155             {
156                 cli.addSystemEnvironment();
157                 cli.addEnvironment( "MAVEN_TERMINATE_CMD", "on" );
158             }
159             catch ( IOException e )
160             {
161                 throw new CommandLineConfigurationException( "Error reading shell environment variables. Reason: "
162                     + e.getMessage(), e );
163             }
164             catch ( Exception e )
165             {
166                 if ( e instanceof RuntimeException )
167                 {
168                     throw (RuntimeException) e;
169                 }
170                 else
171                 {
172                     IllegalStateException error =
173                         new IllegalStateException( "Unknown error retrieving shell environment variables. Reason: "
174                             + e.getMessage() );
175                     error.initCause( e );
176 
177                     throw error;
178                 }
179             }
180         }
181 
182         if ( request.getJavaHome() != null )
183         {
184             cli.addEnvironment( "JAVA_HOME", request.getJavaHome().getAbsolutePath() );
185         }
186 
187         if ( request.getMavenOpts() != null )
188         {
189             cli.addEnvironment( "MAVEN_OPTS", request.getMavenOpts() );
190         }
191 
192         for ( Iterator iterator = request.getShellEnvironments().keySet().iterator(); iterator.hasNext(); )
193         {
194             String key = (String) iterator.next();
195             String value = (String) request.getShellEnvironments().get( key );
196             cli.addEnvironment( key, value );
197         }
198     }
199 
200     protected void setProfiles( InvocationRequest request, Commandline cli )
201     {
202         List profiles = request.getProfiles();
203 
204         if ( ( profiles != null ) && !profiles.isEmpty() )
205         {
206             cli.createArg().setValue( "-P" );
207             cli.createArg().setValue( StringUtils.join( profiles.iterator(), "," ) );
208         }
209 
210     }
211 
212     protected void setGoals( InvocationRequest request, Commandline cli )
213     {
214         List goals = request.getGoals();
215 
216         if ( ( goals != null ) && !goals.isEmpty() )
217         {
218             cli.createArg().setLine( StringUtils.join( goals.iterator(), " " ) );
219         }
220     }
221 
222     protected void setProperties( InvocationRequest request, Commandline cli )
223     {
224         Properties properties = request.getProperties();
225 
226         if ( properties != null )
227         {
228             for ( Iterator it = properties.entrySet().iterator(); it.hasNext(); )
229             {
230                 Map.Entry entry = (Map.Entry) it.next();
231 
232                 String key = (String) entry.getKey();
233                 String value = (String) entry.getValue();
234 
235                 cli.createArg().setValue( "-D" );
236                 cli.createArg().setValue( key + '=' + value );
237             }
238         }
239     }
240 
241     protected void setPomLocation( InvocationRequest request, Commandline cli )
242     {
243         boolean pomSpecified = false;
244 
245         File pom = request.getPomFile();
246         String pomFilename = request.getPomFileName();
247         File baseDirectory = request.getBaseDirectory();
248 
249         if ( pom != null )
250         {
251             pomSpecified = true;
252         }
253         else if ( baseDirectory != null )
254         {
255             if ( baseDirectory.isDirectory() )
256             {
257                 if ( pomFilename != null )
258                 {
259                     pom = new File( baseDirectory, pomFilename );
260 
261                     pomSpecified = true;
262                 }
263                 else
264                 {
265                     pom = new File( baseDirectory, "pom.xml" );
266                 }
267             }
268             else
269             {
270                 logger.warn( "Base directory is a file. Using base directory as POM location." );
271 
272                 pom = baseDirectory;
273 
274                 pomSpecified = true;
275             }
276         }
277 
278         if ( pomSpecified )
279         {
280             try
281             {
282                 File canPom = pom.getCanonicalFile();
283                 pom = canPom;
284             }
285             catch ( IOException e )
286             {
287                 logger.debug( "Failed to canonicalize the POM path: " + pom + ". Using as-is.", e );
288             }
289 
290             if ( !"pom.xml".equals( pom.getName() ) )
291             {
292                 logger.debug( "Specified POM file is not named \'pom.xml\'. "
293                     + "Using the \'-f\' command-line option to accommodate non-standard filename..." );
294 
295                 cli.createArg().setValue( "-f" );
296                 cli.createArg().setValue( pom.getName() );
297             }
298         }
299     }
300 
301     protected void setEnvironmentPaths( InvocationRequest request, Commandline cli )
302     {
303         File workingDirectory = request.getBaseDirectory();
304 
305         if ( workingDirectory == null )
306         {
307             File pomFile = request.getPomFile();
308             if ( pomFile != null )
309             {
310                 workingDirectory = pomFile.getParentFile();
311             }
312         }
313 
314         if ( workingDirectory == null )
315         {
316             workingDirectory = this.workingDirectory;
317         }
318 
319         if ( workingDirectory == null )
320         {
321             workingDirectory = new File( System.getProperty( "user.dir" ) );
322         }
323         else if ( workingDirectory.isFile() )
324         {
325             logger.warn( "Specified base directory (" + workingDirectory + ") is a file."
326                 + " Using its parent directory..." );
327 
328             workingDirectory = workingDirectory.getParentFile();
329         }
330 
331         try
332         {
333             cli.setWorkingDirectory( workingDirectory.getCanonicalPath() );
334         }
335         catch ( IOException e )
336         {
337             logger.debug( "Failed to canonicalize base directory: " + workingDirectory + ". Using as-is.", e );
338 
339             cli.setWorkingDirectory( workingDirectory.getAbsolutePath() );
340         }
341 
342         File localRepositoryDirectory = request.getLocalRepositoryDirectory( this.localRepositoryDirectory );
343 
344         if ( localRepositoryDirectory != null )
345         {
346             try
347             {
348                 File canLRD = localRepositoryDirectory.getCanonicalFile();
349                 localRepositoryDirectory = canLRD;
350             }
351             catch ( IOException e )
352             {
353                 logger.debug( "Failed to canonicalize local repository directory: " + localRepositoryDirectory
354                     + ". Using as-is.", e );
355             }
356 
357             if ( !localRepositoryDirectory.isDirectory() )
358             {
359                 throw new IllegalArgumentException( "Local repository location: \'" + localRepositoryDirectory
360                     + "\' is NOT a directory." );
361             }
362 
363             cli.createArg().setValue( "-D" );
364             cli.createArg().setValue( "maven.repo.local=" + localRepositoryDirectory.getPath() );
365         }
366     }
367 
368     protected void setReactorBehavior( InvocationRequest request, Commandline cli )
369     {
370         // NOTE: The default is "fail-fast"
371         String failureBehavior = request.getFailureBehavior();
372 
373         if ( StringUtils.isNotEmpty( failureBehavior ) )
374         {
375             if ( InvocationRequest.REACTOR_FAIL_AT_END.equals( failureBehavior ) )
376             {
377                 cli.createArg().setValue( "-fae" );
378             }
379             else if ( InvocationRequest.REACTOR_FAIL_NEVER.equals( failureBehavior ) )
380             {
381                 cli.createArg().setValue( "-fn" );
382             }
383         }
384 
385         if ( request.isActivatedReactor() )
386         {
387             cli.createArg().setValue( "-r" );
388             String[] includes = request.getActivatedReactorIncludes();
389             String[] excludes = request.getActivatedReactorExcludes();
390             if ( includes != null )
391             {
392                 cli.createArg().setValue( "-D" );
393                 cli.createArg().setValue( "maven.reactor.includes=" + StringUtils.join( includes, "," ) );
394             }
395             if ( excludes != null )
396             {
397                 cli.createArg().setValue( "-D" );
398                 cli.createArg().setValue( "maven.reactor.excludes=" + StringUtils.join( excludes, "," ) );
399             }
400         }
401     }
402 
403     protected void setFlags( InvocationRequest request, Commandline cli )
404     {
405         if ( !request.isInteractive() )
406         {
407             cli.createArg().setValue( "-B" );
408         }
409 
410         if ( request.isOffline() )
411         {
412             cli.createArg().setValue( "-o" );
413         }
414 
415         if ( request.isUpdateSnapshots() )
416         {
417             cli.createArg().setValue( "-U" );
418         }
419 
420         if ( !request.isRecursive() )
421         {
422             cli.createArg().setValue( "-N" );
423         }
424 
425         if ( request.isDebug() )
426         {
427             cli.createArg().setValue( "-X" );
428         }
429         // this is superceded by -X, if it exists.
430         else if ( request.isShowErrors() )
431         {
432             cli.createArg().setValue( "-e" );
433         }
434 
435         String checksumPolicy = request.getGlobalChecksumPolicy();
436         if ( InvocationRequest.CHECKSUM_POLICY_FAIL.equals( checksumPolicy ) )
437         {
438             cli.createArg().setValue( "-C" );
439         }
440         else if ( InvocationRequest.CHECKSUM_POLICY_WARN.equals( checksumPolicy ) )
441         {
442             cli.createArg().setValue( "-c" );
443         }
444         if ( request.isNonPluginUpdates() )
445         {
446             cli.createArg().setValue( "-npu" );
447         }
448         
449         if ( request.isShowVersion() )
450         {
451             cli.createArg().setValue( "-V" );
452         }
453     }
454 
455     protected File findMavenExecutable()
456         throws CommandLineConfigurationException, IOException
457     {
458         if ( mavenHome == null )
459         {
460             String mavenHomeProperty = System.getProperty( "maven.home" );
461             if ( mavenHomeProperty != null )
462             {
463                 mavenHome = new File( mavenHomeProperty );
464                 if ( !mavenHome.isDirectory() )
465                 {
466                     File binDir = mavenHome.getParentFile();
467                     if ( "bin".equals( binDir.getName() ) )
468                     {
469                         // ah, they specified the mvn
470                         // executable instead...
471                         mavenHome = binDir.getParentFile();
472                     }
473                     else
474                     {
475                         throw new IllegalStateException( "${maven.home} is not specified as a directory: \'"
476                             + mavenHomeProperty + "\'." );
477                     }
478                 }
479             }
480 
481             if ( ( mavenHome == null ) && ( getSystemEnvVars().getProperty( "M2_HOME" ) != null ) )
482             {
483                 mavenHome = new File( getSystemEnvVars().getProperty( "M2_HOME" ) );
484             }
485         }
486 
487         logger.debug( "Using ${maven.home} of: \'" + mavenHome + "\'." );
488 
489         if ( mvnCommand == null )
490         {
491             if ( Os.isFamily( "windows" ) )
492             {
493                 mvnCommand = new File( mavenHome, "/bin/mvn.bat" );
494             }
495             else
496             {
497                 mvnCommand = new File( mavenHome, "/bin/mvn" );
498             }
499 
500             try
501             {
502                 File canonicalMvn = mvnCommand.getCanonicalFile();
503                 mvnCommand = canonicalMvn;
504             }
505             catch ( IOException e )
506             {
507                 logger.debug( "Failed to canonicalize maven executable: " + mvnCommand + ". Using as-is.", e );
508             }
509 
510             if ( !mvnCommand.exists() )
511             {
512                 throw new CommandLineConfigurationException( "Maven executable not found at: " + mvnCommand );
513             }
514         }
515 
516         return mvnCommand;
517     }
518 
519     /**
520      * Wraps a path with quotes to handle paths with spaces. If no spaces are found, the original string is returned.
521      * 
522      * @param path string to wrap if containing spaces
523      * @return quote wrapped string
524      * @deprecated Quoting of command line arguments should be left to the Commandline from plexus-utils.
525      */
526     public String wrapStringWithQuotes( String path )
527     {
528         if ( path.indexOf( " " ) > -1 )
529         {
530             return "\"" + path + "\"";
531         }
532         else
533         {
534             return path;
535         }
536     }
537 
538     private Properties getSystemEnvVars()
539         throws IOException
540     {
541         if ( this.systemEnvVars == null )
542         {
543             // with 1.5 replace with System.getenv()
544             this.systemEnvVars = CommandLineUtils.getSystemEnvVars();
545         }
546         return this.systemEnvVars;
547     }
548 
549     public File getLocalRepositoryDirectory()
550     {
551         return localRepositoryDirectory;
552     }
553 
554     public void setLocalRepositoryDirectory( File localRepositoryDirectory )
555     {
556         this.localRepositoryDirectory = localRepositoryDirectory;
557     }
558 
559     public InvokerLogger getLogger()
560     {
561         return logger;
562     }
563 
564     public void setLogger( InvokerLogger logger )
565     {
566         this.logger = logger;
567     }
568 
569     public File getMavenHome()
570     {
571         return mavenHome;
572     }
573 
574     public void setMavenHome( File mavenHome )
575     {
576         this.mavenHome = mavenHome;
577     }
578 
579     public File getWorkingDirectory()
580     {
581         return workingDirectory;
582     }
583 
584     public void setWorkingDirectory( File workingDirectory )
585     {
586         this.workingDirectory = workingDirectory;
587     }
588 
589 }