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