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 java.io.File;
23  import java.io.FileWriter;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.util.List;
28  
29  import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
30  import org.apache.maven.shared.release.ReleaseResult;
31  import org.apache.maven.shared.release.env.ReleaseEnvironment;
32  import org.codehaus.plexus.component.annotations.Component;
33  import org.codehaus.plexus.component.annotations.Requirement;
34  import org.codehaus.plexus.util.StringUtils;
35  import org.codehaus.plexus.util.cli.CommandLineException;
36  import org.codehaus.plexus.util.cli.Commandline;
37  
38  /**
39   * Fork Maven to executed a series of goals.
40   *
41   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
42   */
43  @Component( role = MavenExecutor.class, hint = "forked-path" )
44  public class ForkedMavenExecutor
45      extends AbstractMavenExecutor
46  {
47      /**
48       * Command line factory.
49       */
50      @Requirement
51      private CommandLineFactory commandLineFactory;
52  
53      /**
54       * @noinspection UseOfSystemOutOrSystemErr
55       */
56      @Override
57      public void executeGoals( File workingDirectory, List<String> goals, ReleaseEnvironment releaseEnvironment,
58                                boolean interactive, String additionalArguments, String pomFileName,
59                                ReleaseResult relResult )
60          throws MavenExecutorException
61      {
62          String mavenPath = null;
63          // if null we use the current one
64          if ( releaseEnvironment.getMavenHome() != null )
65          {
66              mavenPath = releaseEnvironment.getMavenHome().getAbsolutePath();
67          }
68          else
69          {
70              mavenPath = System.getProperty( "maven.home" );
71          }
72  
73          File settingsFile = null;
74          if ( releaseEnvironment.getSettings() != null )
75          {
76              // Have to serialize to a file as if Maven is embedded, there may not actually be a settings.xml on disk
77              try
78              {
79                  settingsFile = File.createTempFile( "release-settings", ".xml" );
80                  SettingsXpp3Writer writer = getSettingsWriter();
81                  
82                  try ( FileWriter fileWriter = new FileWriter( settingsFile ) )
83                  {
84                      writer.write( fileWriter, encryptSettings( releaseEnvironment.getSettings() ) );
85                  }
86              }
87              catch ( IOException e )
88              {
89                  throw new MavenExecutorException( "Could not create temporary file for release settings.xml", e );
90              }
91          }
92          try
93          {
94  
95              Commandline cl =
96                  commandLineFactory.createCommandLine( mavenPath + File.separator + "bin" + File.separator + "mvn" );
97  
98              cl.setWorkingDirectory( workingDirectory.getAbsolutePath() );
99  
100             cl.addEnvironment( "MAVEN_TERMINATE_CMD", "on" );
101 
102             cl.addEnvironment( "M2_HOME", mavenPath );
103 
104             if ( settingsFile != null )
105             {
106                 cl.createArg().setValue( "-s" );
107                 cl.createArg().setFile( settingsFile );
108             }
109 
110             if ( pomFileName != null )
111             {
112                 cl.createArg().setValue( "-f" );
113                 cl.createArg().setValue( pomFileName );
114             }
115 
116             for ( String goal : goals )
117             {
118                 cl.createArg().setValue( goal );
119             }
120 
121             if ( !interactive )
122             {
123                 cl.createArg().setValue( "--batch-mode" );
124             }
125 
126             if ( !StringUtils.isEmpty( additionalArguments ) )
127             {
128                 cl.createArg().setLine( additionalArguments );
129             }
130 
131             TeeOutputStream stdOut = new TeeOutputStream( System.out );
132 
133             TeeOutputStream stdErr = new TeeOutputStream( System.err );
134 
135             try
136             {
137                 relResult.appendInfo( "Executing: " + cl.toString() );
138                 getLogger().info( "Executing: " + cl.toString() );
139 
140                 int result = executeCommandLine( cl, System.in, stdOut, stdErr );
141 
142                 if ( result != 0 )
143                 {
144                     throw new MavenExecutorException( "Maven execution failed, exit code: \'" + result + "\'", result,
145                                                       stdOut.toString(), stdErr.toString() );
146                 }
147             }
148             catch ( CommandLineException e )
149             {
150                 throw new MavenExecutorException( "Can't run goal " + goals, stdOut.toString(), stdErr.toString(), e );
151             }
152             finally
153             {
154                 relResult.appendOutput( stdOut.toString() );
155             }
156         }
157         finally
158         {
159             if ( settingsFile != null && settingsFile.exists() && !settingsFile.delete() )
160             {
161                 settingsFile.deleteOnExit();
162             }
163         }
164     }
165 
166     public void setCommandLineFactory( CommandLineFactory commandLineFactory )
167     {
168         this.commandLineFactory = commandLineFactory;
169     }
170 
171 
172     public static int executeCommandLine( Commandline cl, InputStream systemIn, OutputStream systemOut,
173                                           OutputStream systemErr )
174         throws CommandLineException
175     {
176         if ( cl == null )
177         {
178             throw new IllegalArgumentException( "cl cannot be null." );
179         }
180 
181         Process p = cl.execute();
182 
183         //processes.put( new Long( cl.getPid() ), p );
184 
185         RawStreamPumper inputFeeder = null;
186 
187         if ( systemIn != null )
188         {
189             inputFeeder = new RawStreamPumper( systemIn, p.getOutputStream(), true );
190         }
191 
192         RawStreamPumper outputPumper = new RawStreamPumper( p.getInputStream(), systemOut );
193         RawStreamPumper errorPumper = new RawStreamPumper( p.getErrorStream(), systemErr );
194 
195         if ( inputFeeder != null )
196         {
197             inputFeeder.start();
198         }
199 
200         outputPumper.start();
201 
202         errorPumper.start();
203 
204         try
205         {
206             int returnValue = p.waitFor();
207 
208             if ( inputFeeder != null )
209             {
210                 inputFeeder.setDone();
211             }
212             outputPumper.setDone();
213             errorPumper.setDone();
214 
215             //processes.remove( new Long( cl.getPid() ) );
216 
217             return returnValue;
218         }
219         catch ( InterruptedException ex )
220         {
221             //killProcess( cl.getPid() );
222             throw new CommandLineException( "Error while executing external command, process killed.", ex );
223         }
224         finally
225         {
226             try
227             {
228                 errorPumper.closeInput();
229             }
230             catch ( IOException e )
231             {
232                 //ignore
233             }
234             try
235             {
236                 outputPumper.closeInput();
237             }
238             catch ( IOException e )
239             {
240                 //ignore
241             }
242             if ( inputFeeder != null )
243             {
244                 try
245                 {
246                     inputFeeder.closeOutput();
247                 }
248                 catch ( IOException e )
249                 {
250                     //ignore
251                 }
252             }
253         }
254     }
255 
256 
257 }