blob: c14e08e6569dacad2ccd79da17f835e54f8691c9 [file] [log] [blame]
package org.apache.maven.plugins.linkcheck;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import org.apache.commons.lang.SystemUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.model.Profile;
import org.apache.maven.model.Reporting;
import org.apache.maven.project.MavenProject;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
import org.apache.maven.shared.invoker.DefaultInvoker;
import org.apache.maven.shared.invoker.InvocationOutputHandler;
import org.apache.maven.shared.invoker.InvocationRequest;
import org.apache.maven.shared.invoker.InvocationResult;
import org.apache.maven.shared.invoker.Invoker;
import org.apache.maven.shared.invoker.MavenInvocationException;
import org.apache.maven.shared.invoker.PrintStreamHandler;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.WriterFactory;
import org.codehaus.plexus.util.cli.CommandLineUtils;
/**
* @author ltheussl
* @since 1.1
*/
public class SiteInvoker
{
private final ArtifactRepository localRepository;
private final Log log;
public SiteInvoker( ArtifactRepository localRepository, Log log )
{
this.localRepository = localRepository;
this.log = log;
}
/**
* Invoke Maven for the <code>site</code> phase for a temporary Maven project using
* <code>tmpReportingOutputDirectory</code> as <code>${project.reporting.outputDirectory}</code>.
* This is a workaround to be sure that all site files have been correctly generated. <br/>
* <b>Note 1</b>: the Maven Home should be defined in the <code>maven.home</code> Java system property
* or defined in <code>M2_HOME</code> system env variables.
* <b>Note 2</be>: we can't use <code>siteOutputDirectory</code> param from site plugin because some plugins
* <code>${project.reporting.outputDirectory}</code> in their conf.
*
* @param project the MavenProject to invoke the site on. Not null.
* @param tmpReportingOutputDirectory not null
* @throws IOException if any
*/
public void invokeSite( MavenProject project, File tmpReportingOutputDirectory )
throws IOException
{
String mavenHome = getMavenHome();
if ( StringUtils.isEmpty( mavenHome ) )
{
// CHECKSTYLE_OFF: LineLength
getLog().error( "Could NOT invoke Maven because no Maven Home is defined. "
+ "You need to set the M2_HOME system env variable or a 'maven.home' Java system property." );
// CHECKSTYLE_ON: LineLength
return;
}
// invoker site parameters
List goals = Collections.singletonList( "site" );
Properties properties = new Properties();
properties.put( "linkcheck.skip", "true" ); // to stop recursion
File invokerLog =
FileUtils.createTempFile( "invoker-site-plugin", ".txt", new File( project.getBuild().getDirectory() ) );
// clone project and set a new reporting output dir
MavenProject clone;
try
{
clone = (MavenProject) project.clone();
}
catch ( CloneNotSupportedException e )
{
IOException ioe = new IOException( "CloneNotSupportedException: " + e.getMessage() );
ioe.setStackTrace( e.getStackTrace() );
throw ioe;
}
// MLINKCHECK-1
if ( clone.getOriginalModel().getReporting() == null )
{
clone.getOriginalModel().setReporting( new Reporting() );
}
clone.getOriginalModel().getReporting().setOutputDirectory( tmpReportingOutputDirectory.getAbsolutePath() );
List profileIds = getActiveProfileIds( clone );
// create the original model as tmp pom file for the invoker
File tmpProjectFile = FileUtils.createTempFile( "pom", ".xml", project.getBasedir() );
Writer writer = null;
try
{
writer = WriterFactory.newXmlWriter( tmpProjectFile );
clone.writeOriginalModel( writer );
writer.close();
writer = null;
}
finally
{
IOUtil.close( writer );
}
// invoke it
try
{
invoke( tmpProjectFile, invokerLog, mavenHome, goals, profileIds, properties );
}
finally
{
if ( !getLog().isDebugEnabled() )
{
tmpProjectFile.delete();
}
}
}
private static List getActiveProfileIds( MavenProject clone )
{
List profileIds = new ArrayList();
for ( Object o : clone.getActiveProfiles() )
{
profileIds.add( ( (Profile) o ).getId() );
}
return profileIds;
}
/**
* @param projectFile not null, should be in the ${project.basedir}
* @param invokerLog not null
* @param mavenHome not null
* @param goals the list of goals
* @param properties the properties for the invoker
*/
private void invoke( File projectFile, File invokerLog, String mavenHome, List goals, List activeProfiles,
Properties properties )
{
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome( new File( mavenHome ) );
File localRepoDir = new File( localRepository.getBasedir() );
invoker.setLocalRepositoryDirectory( localRepoDir );
InvocationRequest request = new DefaultInvocationRequest();
request.setLocalRepositoryDirectory( localRepoDir );
// request.setUserSettingsFile( settingsFile );
request.setInteractive( false );
request.setShowErrors( getLog().isErrorEnabled() );
request.setDebug( getLog().isDebugEnabled() );
// request.setShowVersion( false );
request.setBaseDirectory( projectFile.getParentFile() );
request.setPomFile( projectFile );
request.setGoals( goals );
request.setProperties( properties );
request.setProfiles( activeProfiles );
File javaHome = getJavaHome();
if ( javaHome != null )
{
request.setJavaHome( javaHome );
}
InvocationResult invocationResult;
try
{
if ( getLog().isDebugEnabled() )
{
getLog().debug( "Invoking Maven for the goals: " + goals + " with properties=" + properties );
}
invocationResult = invoke( invoker, request, invokerLog, goals, properties, null );
}
catch ( MavenInvocationException e )
{
getLog().error( "Error when invoking Maven, consult the invoker log." );
getLog().debug( e );
return;
}
String invokerLogContent = null;
Reader reader = null;
try
{
reader = ReaderFactory.newReader( invokerLog, "UTF-8" );
invokerLogContent = IOUtil.toString( reader );
reader.close();
reader = null;
}
catch ( IOException e )
{
getLog().error( "IOException: " + e.getMessage() );
getLog().debug( e );
}
finally
{
IOUtil.close( reader );
}
if ( invokerLogContent != null && invokerLogContent.contains( "Error occurred during initialization of VM" ) )
{
getLog().info( "Error occurred during initialization of VM, try to use an empty MAVEN_OPTS." );
if ( getLog().isDebugEnabled() )
{
getLog().debug( "Reinvoking Maven for the goals: " + goals + " with an empty MAVEN_OPTS" );
}
try
{
invocationResult = invoke( invoker, request, invokerLog, goals, properties, "" );
}
catch ( MavenInvocationException e )
{
getLog().error( "Error when reinvoking Maven, consult the invoker log." );
getLog().debug( e );
return;
}
}
if ( invocationResult.getExitCode() != 0 )
{
if ( getLog().isErrorEnabled() )
{
getLog().error( "Error when invoking Maven, consult the invoker log file: "
+ invokerLog.getAbsolutePath() );
}
}
}
/**
* @param invoker not null
* @param request not null
* @param invokerLog not null
* @param goals the list of goals
* @param properties the properties for the invoker
* @param mavenOpts could be null
* @return the invocation result
* @throws MavenInvocationException if any
*/
private InvocationResult invoke( Invoker invoker, InvocationRequest request, File invokerLog, List goals,
Properties properties, String mavenOpts )
throws MavenInvocationException
{
PrintStream ps;
OutputStream os = null;
if ( invokerLog != null )
{
if ( getLog().isDebugEnabled() )
{
getLog().debug( "Using " + invokerLog.getAbsolutePath() + " to log the invoker" );
}
try
{
if ( !invokerLog.exists() )
{
invokerLog.getParentFile().mkdirs();
}
os = new FileOutputStream( invokerLog );
ps = new PrintStream( os, true, "UTF-8" );
}
catch ( FileNotFoundException e )
{
if ( getLog().isErrorEnabled() )
{
getLog().error( "FileNotFoundException: " + e.getMessage()
+ ". Using System.out to log the invoker." );
}
ps = System.out;
}
catch ( UnsupportedEncodingException e )
{
if ( getLog().isErrorEnabled() )
{
getLog().error( "UnsupportedEncodingException: " + e.getMessage()
+ ". Using System.out to log the invoker." );
}
ps = System.out;
}
}
else
{
getLog().debug( "Using System.out to log the invoker." );
ps = System.out;
}
if ( mavenOpts != null )
{
request.setMavenOpts( mavenOpts );
}
InvocationOutputHandler outputHandler = new PrintStreamHandler( ps, false );
request.setOutputHandler( outputHandler );
request.setErrorHandler( outputHandler );
outputHandler.consumeLine( "Invoking Maven for the goals: " + goals + " with properties=" + properties );
outputHandler.consumeLine( "" );
outputHandler.consumeLine( "M2_HOME=" + getMavenHome() );
outputHandler.consumeLine( "MAVEN_OPTS=" + getMavenOpts() );
outputHandler.consumeLine( "JAVA_HOME=" + getJavaHome() );
outputHandler.consumeLine( "JAVA_OPTS=" + getJavaOpts() );
outputHandler.consumeLine( "" );
try
{
return invoker.execute( request );
}
finally
{
IOUtil.close( os );
ps = null;
}
}
/**
* @return the Maven home defined in the <code>maven.home</code> system property or defined
* in <code>M2_HOME</code> system env variables or null if never setted.
* @see #invoke(Invoker, InvocationRequest, File, List, Properties, String)
*/
private String getMavenHome()
{
String mavenHome = System.getProperty( "maven.home" );
if ( mavenHome == null )
{
try
{
mavenHome = CommandLineUtils.getSystemEnvVars().getProperty( "M2_HOME" );
}
catch ( IOException e )
{
getLog().error( "IOException: " + e.getMessage() );
getLog().debug( e );
}
}
File m2Home = new File( mavenHome );
if ( !m2Home.exists() )
{
getLog().error( "Cannot find Maven application directory. Either specify \'maven.home\' "
+ "system property, or M2_HOME environment variable." );
}
return mavenHome;
}
/**
* @return the <code>MAVEN_OPTS</code> env variable value or null if not setted.
* @see #invoke(Invoker, InvocationRequest, File, List, Properties, String)
*/
private String getMavenOpts()
{
String mavenOpts = null;
try
{
mavenOpts = CommandLineUtils.getSystemEnvVars().getProperty( "MAVEN_OPTS" );
}
catch ( IOException e )
{
getLog().error( "IOException: " + e.getMessage() );
getLog().debug( e );
}
return mavenOpts;
}
/**
* @return the <code>JAVA_HOME</code> from System.getProperty( "java.home" )
* By default, <code>System.getProperty( "java.home" ) = JRE_HOME</code> and <code>JRE_HOME</code> should be
* in the <code>JDK_HOME</code> or null if not setted.
* @see #invoke(Invoker, InvocationRequest, File, List, Properties, String)
*/
private File getJavaHome()
{
File javaHome;
if ( SystemUtils.IS_OS_MAC_OSX )
{
javaHome = SystemUtils.getJavaHome();
}
else
{
javaHome = new File( SystemUtils.getJavaHome(), ".." );
}
if ( javaHome == null || !javaHome.exists() )
{
try
{
javaHome = new File( CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_HOME" ) );
}
catch ( IOException e )
{
getLog().error( "IOException: " + e.getMessage() );
getLog().debug( e );
}
}
if ( javaHome == null || !javaHome.exists() )
{
getLog().error( "Cannot find Java application directory. Either specify \'java.home\' "
+ "system property, or JAVA_HOME environment variable." );
}
return javaHome;
}
/**
* @return the <code>JAVA_OPTS</code> env variable value or null if not setted.
* @see #invoke(Invoker, InvocationRequest, File, List, Properties, String)
*/
private String getJavaOpts()
{
String javaOpts = null;
try
{
javaOpts = CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_OPTS" );
}
catch ( IOException e )
{
getLog().error( "IOException: " + e.getMessage() );
getLog().debug( e );
}
return javaOpts;
}
private Log getLog()
{
return log;
}
}