All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scoverage.plugin.SCoveragePreCompileMojo Maven / Gradle / Ivy

/*
 * Copyright 2014-2015 Grzegorz Slowikowski (gslowikowski at gmail dot com)
 *
 * Licensed 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.
 */

package org.scoverage.plugin;

import java.io.File;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.StringUtils;

/**
 * Configures project for compilation with SCoverage instrumentation.
 * 
*
* Supported compiler plugins: * *
* This is internal mojo, executed in forked {@code cobertura} life cycle. *
* * @author Grzegorz Slowikowski * @since 1.0.0 */ @Mojo( name = "pre-compile", defaultPhase = LifecyclePhase.GENERATE_RESOURCES ) public class SCoveragePreCompileMojo extends AbstractMojo { /** * Allows SCoverage to be skipped. *
* * @since 1.0.0 */ @Parameter( property = "scoverage.skip", defaultValue = "false" ) private boolean skip; /** * Scala version used for compiler plugin artifact resolution. *
    *
  • if specified, and starts with {@code 2.10.} - {@code scalac-scoverage-plugin_2.10} will be used
  • *
  • if specified, and starts with {@code 2.11.} - {@code scalac-scoverage-plugin_2.11} will be used
  • *
  • if specified, but does not start with {@code 2.10.} or with {@code 2.11.} or is not specified - plugin execution will be skipped
  • *
* * @since 1.0.0 */ @Parameter( property = "scala.version" ) private String scalaVersion; /** * Directory where the coverage files should be written. *
* * @since 1.0.0 */ @Parameter( property = "scoverage.dataDirectory", defaultValue = "${project.build.directory}/scoverage-data", required = true, readonly = true ) private File dataDirectory; /** * Semicolon-separated list of regular expressions for packages to exclude, "(empty)" for default package. *
*
* Example: * {@code (empty);Reverse.*;.*AuthService.*;models\.data\..*} *
*
* See https://github.com/scoverage/sbt-scoverage#exclude-classes-and-packages for additional documentation. *
* * @since 1.0.0 */ @Parameter( property = "scoverage.excludedPackages", defaultValue = "" ) private String excludedPackages; /** * Semicolon separated list of regular expressions for source paths to exclude. *
* * @since 1.0.0 */ @Parameter( property = "scoverage.excludedFiles", defaultValue = "" ) private String excludedFiles; /** * See https://github.com/scoverage/sbt-scoverage#highlighting. *
* * @since 1.0.0 */ @Parameter( property = "scoverage.highlighting", defaultValue = "false" ) private boolean highlighting; /** * Force scalac-scoverage-plugin version used. *
* * @since 1.0.0 */ @Parameter( property = "scoverage.scalacPluginVersion", defaultValue = "" ) private String scalacPluginVersion; /** * Maven project to interact with. */ @Parameter( defaultValue = "${project}", readonly = true, required = true ) private MavenProject project; /** * All Maven projects in the reactor. */ @Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true ) private List reactorProjects; /** * Artifact factory used to look up artifacts in the remote repository. */ @Component private ArtifactFactory factory; /** * Artifact resolver used to resolve artifacts. */ @Component private ArtifactResolver resolver; /** * Location of the local repository. */ @Parameter( property = "localRepository", readonly = true, required = true ) private ArtifactRepository localRepo; /** * Remote repositories used by the resolver */ @Parameter( property = "project.remoteArtifactRepositories", readonly = true, required = true ) private List remoteRepos; /** * List of artifacts this plugin depends on. */ @Parameter( property = "plugin.artifacts", readonly = true, required = true ) private List pluginArtifacts; /** * Configures project for compilation with SCoverage instrumentation. * * @throws MojoExecutionException if unexpected problem occurs */ @Override public void execute() throws MojoExecutionException { if ( "pom".equals( project.getPackaging() ) ) { getLog().info( "Skipping SCoverage execution for project with packaging type 'pom'" ); //for aggragetor mojo - list of submodules: List modules = project.getCollectedProjects(); return; } if ( skip ) { getLog().info( "Skipping Scoverage execution" ); return; } long ts = System.currentTimeMillis(); String scalaMainVersion = null; String resolvedScalaVersion = resolveScalaVersion(); if ( resolvedScalaVersion != null ) { if ( resolvedScalaVersion.startsWith( "2.10." ) ) { scalaMainVersion = "2.10"; } else if ( resolvedScalaVersion.startsWith( "2.11." ) ) { scalaMainVersion = "2.11"; } else { getLog().warn( String.format( "Skipping SCoverage execution - unsupported Scala version \"%s\"", resolvedScalaVersion ) ); return; } } else { getLog().warn( "Skipping SCoverage execution - Scala version not set" ); return; } File classesDirectory = new File( project.getBuild().getOutputDirectory() ); File scoverageClassesDirectory = new File( classesDirectory.getParentFile(), "scoverage-classes" ); project.getBuild().setOutputDirectory( scoverageClassesDirectory.getAbsolutePath() ); for ( MavenProject reactorProject : reactorProjects ) { if ( reactorProject != project ) // TODO - how to include only dependent reactor projects? { classesDirectory = new File( reactorProject.getBuild().getOutputDirectory() ); if ( !"scoverage-classes".equals( classesDirectory.getName() ) ) { scoverageClassesDirectory = new File( classesDirectory.getParentFile(), "scoverage-classes" ); if ( scoverageClassesDirectory.isDirectory() ) { reactorProject.getBuild().setOutputDirectory( scoverageClassesDirectory.getAbsolutePath() ); } //else //{ // SCoverage probably skipped for that module // TODO add info message //} } } } try { Artifact pluginArtifact = getScalaScoveragePluginArtifact( scalaMainVersion ); Artifact runtimeArtifact = getScalaScoverageRuntimeArtifact( scalaMainVersion ); if ( pluginArtifact == null ) { return; // scoverage plugin will not be configured } addScoverageDependenciesToTestClasspath( runtimeArtifact ); String arg = DATA_DIR_OPTION + dataDirectory.getAbsolutePath(); String _scalacOptions = quoteArgument( arg ); String addScalacArgs = arg; if ( !StringUtils.isEmpty( excludedPackages ) ) { arg = EXCLUDED_PACKAGES_OPTION + excludedPackages.replace( "(empty)", "" ); _scalacOptions = _scalacOptions + SPACE + quoteArgument( arg ); addScalacArgs = addScalacArgs + PIPE + arg; } if ( !StringUtils.isEmpty( excludedFiles ) ) { arg = EXCLUDED_FILES_OPTION + excludedFiles; _scalacOptions = _scalacOptions + SPACE + quoteArgument( arg ); addScalacArgs = addScalacArgs + PIPE + arg; } if ( highlighting ) { _scalacOptions = _scalacOptions + SPACE + "-Yrangepos"; addScalacArgs = addScalacArgs + PIPE + "-Yrangepos"; } String _scalacPlugins = String.format( "%s:%s:%s", pluginArtifact.getGroupId(), pluginArtifact.getArtifactId(), pluginArtifact.getVersion() ); arg = PLUGIN_OPTION + pluginArtifact.getFile().getAbsolutePath(); addScalacArgs = addScalacArgs + PIPE + arg; Properties projectProperties = project.getProperties(); // for sbt-compiler-maven-plugin (version 1.0.0-beta5+) setProperty( projectProperties, "sbt._scalacOptions", _scalacOptions ); // for sbt-compiler-maven-plugin (version 1.0.0-beta5+) setProperty( projectProperties, "sbt._scalacPlugins", _scalacPlugins ); // for scala-maven-plugin (version 3.0.0+) setProperty( projectProperties, "addScalacArgs", addScalacArgs ); // for scala-maven-plugin (version 3.1.0+) setProperty( projectProperties, "analysisCacheFile", "${project.build.directory}/scoverage-analysis/compile" ); // for maven-surefire-plugin and scalatest-maven-plugin setProperty( projectProperties, "maven.test.failure.ignore", "true" ); } catch ( ArtifactNotFoundException e ) { throw new MojoExecutionException( "SCoverage preparation failed", e ); } catch ( ArtifactResolutionException e ) { throw new MojoExecutionException( "SCoverage preparation failed", e ); } long te = System.currentTimeMillis(); getLog().debug( String.format( "Mojo execution time: %d ms", te - ts ) ); } // Private utility methods private static final String SCALA_LIBRARY_GROUP_ID = "org.scala-lang"; private static final String SCALA_LIBRARY_ARTIFACT_ID = "scala-library"; private static final String DATA_DIR_OPTION = "-P:scoverage:dataDir:"; private static final String EXCLUDED_PACKAGES_OPTION = "-P:scoverage:excludedPackages:"; private static final String EXCLUDED_FILES_OPTION = "-P:scoverage:excludedFiles:"; private static final String PLUGIN_OPTION = "-Xplugin:"; private static final char DOUBLE_QUOTE = '\"'; private static final char SPACE = ' '; private static final char PIPE = '|'; private String quoteArgument( String arg ) { return arg.indexOf( SPACE ) >= 0 ? DOUBLE_QUOTE + arg + DOUBLE_QUOTE : arg; } private String resolveScalaVersion() { String result = scalaVersion; if ( result == null ) { // check project direct dependencies (transitive dependencies cannot be checked in this Maven lifecycle phase) List dependencies = project.getDependencies(); for ( Dependency dependency: dependencies ) { if ( SCALA_LIBRARY_GROUP_ID.equals( dependency.getGroupId() ) && SCALA_LIBRARY_ARTIFACT_ID.equals( dependency.getArtifactId() ) ) { result = dependency.getVersion(); break; } } } return result; } private void setProperty( Properties projectProperties, String propertyName, String newValue ) { if ( projectProperties.containsKey( propertyName ) ) { String oldValue = projectProperties.getProperty( propertyName ); projectProperties.put( "scoverage.backup." + propertyName, oldValue ); } else { projectProperties.remove( "scoverage.backup." + propertyName ); } if ( newValue != null ) { projectProperties.put( propertyName, newValue ); } else { projectProperties.remove( propertyName ); } } private Artifact getScalaScoveragePluginArtifact( String scalaMainVersion ) throws ArtifactNotFoundException, ArtifactResolutionException { Artifact result = null; String resolvedScalacPluginVersion = scalacPluginVersion; if ( resolvedScalacPluginVersion == null || "".equals( resolvedScalacPluginVersion ) ) { for ( Artifact artifact : pluginArtifacts ) { if ( "org.scoverage".equals( artifact.getGroupId() ) && "scalac-scoverage-plugin_2.10".equals( artifact.getArtifactId() ) ) { if ( "2.10".equals( scalaMainVersion ) ) { return artifact; // shortcut, use the same artifact plugin uses } resolvedScalacPluginVersion = artifact.getVersion(); break; } } } result = getResolvedArtifact( "org.scoverage", "scalac-scoverage-plugin_" + scalaMainVersion, resolvedScalacPluginVersion ); return result; } private Artifact getScalaScoverageRuntimeArtifact( String scalaMainVersion ) throws ArtifactNotFoundException, ArtifactResolutionException { Artifact result = null; String resolvedScalacRuntimeVersion = scalacPluginVersion; if ( resolvedScalacRuntimeVersion == null || "".equals( resolvedScalacRuntimeVersion ) ) { for ( Artifact artifact : pluginArtifacts ) { if ( "org.scoverage".equals( artifact.getGroupId() ) && "scalac-scoverage-plugin_2.10".equals( artifact.getArtifactId() ) ) { resolvedScalacRuntimeVersion = artifact.getVersion(); break; } } } result = getResolvedArtifact( "org.scoverage", "scalac-scoverage-runtime_" + scalaMainVersion, resolvedScalacRuntimeVersion ); return result; } /** * We need to tweak our test classpath for Scoverage. * * @throws MojoExecutionException */ private void addScoverageDependenciesToTestClasspath( Artifact scalaScoveragePluginArtifact ) throws MojoExecutionException { Artifact providedArtifact = artifactScopeToProvided( scalaScoveragePluginArtifact ); //if ( project.getDependencyArtifacts() != null )//TODO - remove "if"? //{ Set set = new LinkedHashSet( project.getDependencyArtifacts() ); set.add( providedArtifact ); project.setDependencyArtifacts( set ); //} } /** * Use provided instead of just test, so it's available on both compile and test classpath (MCOBERTURA-26) * * @param artifact * @return re-scoped artifact */ private Artifact artifactScopeToProvided( Artifact artifact ) { return factory.createArtifact( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), Artifact.SCOPE_PROVIDED, artifact.getType() ); } private Artifact getResolvedArtifact( String groupId, String artifactId, String version ) throws ArtifactNotFoundException, ArtifactResolutionException { Artifact artifact = factory.createArtifact( groupId, artifactId, version, Artifact.SCOPE_RUNTIME, "jar" ); resolver.resolve( artifact, remoteRepos, localRepo ); return artifact; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy