| 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.plugin.logging.Log; |
| import org.apache.maven.project.MavenProject; |
| 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.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; |
| } |
| |
| /** |
| * <p>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. |
| * </p> |
| * <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</b>: 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 ( mavenHome == null || mavenHome.isEmpty() ) |
| { |
| // 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<String> 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<String> profileIds = getActiveProfileIds( clone ); |
| |
| // create the original model as tmp pom file for the invoker |
| File tmpProjectFile = FileUtils.createTempFile( "pom", ".xml", project.getBasedir() ); |
| |
| try ( Writer writer = WriterFactory.newXmlWriter( tmpProjectFile ) ) |
| { |
| clone.writeOriginalModel( writer ); |
| } |
| |
| // invoke it |
| try |
| { |
| invoke( tmpProjectFile, invokerLog, mavenHome, goals, profileIds, properties ); |
| } |
| finally |
| { |
| if ( !getLog().isDebugEnabled() ) |
| { |
| tmpProjectFile.delete(); |
| } |
| } |
| } |
| |
| private static List<String> getActiveProfileIds( MavenProject clone ) |
| { |
| List<String> 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<String> goals, |
| List<String> 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.setBatchMode( true ); |
| 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; |
| |
| try ( Reader reader = ReaderFactory.newReader( invokerLog, "UTF-8" ) ) |
| { |
| invokerLogContent = IOUtil.toString( reader ); |
| } |
| catch ( IOException e ) |
| { |
| getLog().error( "IOException: " + e.getMessage() ); |
| getLog().debug( e ); |
| } |
| |
| 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<String> 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 ); |
| |
| try |
| { |
| 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( "" ); |
| } |
| catch ( IOException e ) |
| { |
| throw new MavenInvocationException( e.getMessage(), e.getCause() ); |
| } |
| |
| 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; |
| } |
| } |