View Javadoc
1   package org.apache.maven.shared.release.exec;
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 javax.inject.Inject;
23  import javax.inject.Named;
24  import javax.inject.Singleton;
25  
26  import java.io.File;
27  import java.io.FileWriter;
28  import java.io.IOException;
29  import java.util.ArrayList;
30  import java.util.List;
31  
32  import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
33  import org.apache.maven.shared.invoker.DefaultInvocationRequest;
34  import org.apache.maven.shared.invoker.DefaultInvoker;
35  import org.apache.maven.shared.invoker.InvocationRequest;
36  import org.apache.maven.shared.invoker.InvocationResult;
37  import org.apache.maven.shared.invoker.Invoker;
38  import org.apache.maven.shared.invoker.InvokerLogger;
39  import org.apache.maven.shared.invoker.MavenInvocationException;
40  import org.apache.maven.shared.release.ReleaseResult;
41  import org.apache.maven.shared.release.env.ReleaseEnvironment;
42  import org.apache.maven.shared.release.util.MavenCrypto;
43  import org.slf4j.Logger;
44  
45  /**
46   * Fork Maven using the maven-invoker shared library.
47   */
48  @Singleton
49  @Named( "invoker" )
50  public class InvokerMavenExecutor
51          extends AbstractMavenExecutor
52  {
53      @Inject
54      public InvokerMavenExecutor( MavenCrypto mavenCrypto )
55      {
56          super( mavenCrypto );
57      }
58  
59      @Override
60      public void executeGoals( File workingDirectory, List<String> goals, ReleaseEnvironment releaseEnvironment,
61                                boolean interactive, String additionalArguments, String pomFileName,
62                                ReleaseResult result )
63              throws MavenExecutorException
64      {
65          InvokerLogger bridge = getInvokerLogger();
66  
67          Invoker invoker = new DefaultInvoker()
68                  .setMavenHome( releaseEnvironment.getMavenHome() )
69                  .setLocalRepositoryDirectory( releaseEnvironment.getLocalRepositoryDirectory() )
70                  .setLogger( bridge );
71  
72          InvocationRequest req = new DefaultInvocationRequest()
73                  .setDebug( getLogger().isDebugEnabled() )
74                  .setBaseDirectory( workingDirectory )
75                  // fix for MRELEASE-1105
76                  //.addShellEnvironment( "MAVEN_DEBUG_OPTS", "" )
77                  .setBatchMode( true )
78                  .setOutputHandler( getLogger()::info )
79                  .setErrorHandler( getLogger()::error );
80  
81          if ( pomFileName != null )
82          {
83              req.setPomFileName( pomFileName );
84          }
85  
86          File settingsFile = null;
87          if ( releaseEnvironment.getSettings() != null )
88          {
89              // Have to serialize to a file as if Maven is embedded, there may not actually be a settings.xml on disk
90              try
91              {
92                  settingsFile = File.createTempFile( "release-settings", ".xml" );
93                  SettingsXpp3Writer writer = getSettingsWriter();
94  
95                  try ( FileWriter fileWriter = new FileWriter( settingsFile ) )
96                  {
97                      writer.write( fileWriter, encryptSettings( releaseEnvironment.getSettings() ) );
98                  }
99                  req.setUserSettingsFile( settingsFile );
100             }
101             catch ( IOException e )
102             {
103                 throw new MavenExecutorException( "Could not create temporary file for release settings.xml", e );
104             }
105         }
106 
107         try
108         {
109             List<String> targetGoals = new ArrayList<>( goals );
110 
111             if ( additionalArguments != null && !additionalArguments.isEmpty() )
112             {
113                 // additionalArguments will be parsed be MavenInvoker
114                 targetGoals.add( additionalArguments );
115             }
116 
117             req.setGoals( targetGoals );
118 
119             try
120             {
121                 InvocationResult invocationResult = invoker.execute( req );
122 
123                 if ( invocationResult.getExecutionException() != null )
124                 {
125                     throw new MavenExecutorException( "Error executing Maven.",
126                                                       invocationResult.getExecutionException() );
127                 }
128 
129                 if ( invocationResult.getExitCode() != 0 )
130                 {
131                     throw new MavenExecutorException(
132                         "Maven execution failed, exit code: " + invocationResult.getExitCode(),
133                         invocationResult.getExitCode() );
134                 }
135             }
136             catch ( MavenInvocationException e )
137             {
138                 throw new MavenExecutorException( "Failed to invoke Maven build.", e );
139             }
140         }
141         finally
142         {
143             if ( settingsFile != null && settingsFile.exists() && !settingsFile.delete() )
144             {
145                 settingsFile.deleteOnExit();
146             }
147         }
148     }
149 
150     /**
151      * <p>getInvokerLogger.</p>
152      *
153      * @return a {@link org.apache.maven.shared.invoker.InvokerLogger} object
154      */
155     protected InvokerLogger getInvokerLogger()
156     {
157         return new LoggerBridge( getLogger() );
158     }
159 
160     private static final class LoggerBridge
161             implements InvokerLogger
162     {
163 
164         private final Logger logger;
165 
166         LoggerBridge( Logger logger )
167         {
168             this.logger = logger;
169         }
170 
171         @Override
172         public void debug( String message, Throwable error )
173         {
174             logger.debug( message, error );
175         }
176 
177         @Override
178         public void debug( String message )
179         {
180             logger.debug( message );
181         }
182 
183         @Override
184         public void error( String message, Throwable error )
185         {
186             logger.error( message, error );
187         }
188 
189         @Override
190         public void error( String message )
191         {
192             logger.error( message );
193         }
194 
195         @Override
196         public void fatalError( String message, Throwable error )
197         {
198             logger.error( message, error );
199         }
200 
201         @Override
202         public void fatalError( String message )
203         {
204             logger.error( message );
205         }
206 
207         @Override
208         public int getThreshold()
209         {
210             return InvokerLogger.DEBUG;
211         }
212 
213         @Override
214         public void info( String message, Throwable error )
215         {
216             logger.info( message, error );
217         }
218 
219         @Override
220         public void info( String message )
221         {
222             logger.info( message );
223         }
224 
225         @Override
226         public boolean isDebugEnabled()
227         {
228             return logger.isDebugEnabled();
229         }
230 
231         @Override
232         public boolean isErrorEnabled()
233         {
234             return logger.isErrorEnabled();
235         }
236 
237         @Override
238         public boolean isFatalErrorEnabled()
239         {
240             return logger.isErrorEnabled();
241         }
242 
243         @Override
244         public boolean isInfoEnabled()
245         {
246             return logger.isInfoEnabled();
247         }
248 
249         @Override
250         public boolean isWarnEnabled()
251         {
252             return logger.isWarnEnabled();
253         }
254 
255         @Override
256         public void setThreshold( int level )
257         {
258             // NOTE:
259             // logger.setThreshold( level )
260             // is not supported in plexus-container-default:1.0-alpha-9 as used in Maven 2.x
261         }
262 
263         @Override
264         public void warn( String message, Throwable error )
265         {
266             logger.warn( message, error );
267         }
268 
269         @Override
270         public void warn( String message )
271         {
272             logger.warn( message );
273         }
274     }
275 
276 }