| 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; |
| } |
| } |