com.atlassian.maven.plugin.clover.internal.instrumentation.AbstractInstrumenter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of maven-clover2-plugin Show documentation
Show all versions of maven-clover2-plugin Show documentation
Maven plugin for Clover.
MIGRATION NOTICE: Since next major Clover release this plugin will be renamed to
com.atlassian.maven.plugins:clover-maven-plugin. Thus, goals will also be renamed, e.g.
'clover2:setup' will become 'clover:setup'.
The newest version!
package com.atlassian.maven.plugin.clover.internal.instrumentation;
/*
* 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 com.atlassian.clover.CloverInstr;
import com.atlassian.clover.Logger;
import com.atlassian.clover.spi.lang.Language;
import com.atlassian.maven.plugin.clover.MvnLogger;
import com.atlassian.maven.plugin.clover.internal.CompilerConfiguration;
import com.atlassian.maven.plugin.clover.internal.scanner.CloverSourceScanner;
import com.atlassian.maven.plugin.clover.internal.scanner.LanguageFileExtensionFilter;
import com.google.common.collect.Iterables;
import org.apache.maven.plugin.MojoExecutionException;
import org.codehaus.plexus.util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Code common for instrumentation of various source roots (main sources, test sources).
*/
public abstract class AbstractInstrumenter {
private CompilerConfiguration configuration;
String outputSourceDirectory;
private static final String PROP_PROJECT_BUILD_SOURCEENCODING = "project.build.sourceEncoding";
public AbstractInstrumenter(final CompilerConfiguration configuration, final String outputSourceDirectory) {
this.configuration = configuration;
this.outputSourceDirectory = outputSourceDirectory;
}
protected CompilerConfiguration getConfiguration() {
return this.configuration;
}
/**
*
* @throws MojoExecutionException when instrumentation fails
* @see com.atlassian.maven.plugin.clover.CloverInstrumentInternalMojo#calcIncludedFilesForGroovy()
* @see com.atlassian.maven.plugin.clover.CloverInstrumentInternalMojo#redirectOutputDirectories()
*/
public void instrument() throws MojoExecutionException {
final CloverSourceScanner scanner = getSourceScanner();
// get source files to be instrumented, but only for Java as they will be instrumented by CloverInstr
final Map javaFilesToInstrument = scanner.getSourceFilesToInstrument(LanguageFileExtensionFilter.JAVA_LANGUAGE, true);
if (javaFilesToInstrument.isEmpty()) {
getConfiguration().getLog().info("No Clover instrumentation done on source files in: "
+ getCompileSourceRoots() + " as no matching sources files found (JAVA_LANGUAGE)");
} else {
instrumentSources(javaFilesToInstrument, outputSourceDirectory);
}
// find groovy files in all compilation roots and copy them
//
// 1) in case when 'src/main/java' (or 'src/test/java') contains *.groovy source files (this is a trick possible
// with a groovy-eclipse-plugin, see http://groovy.codehaus.org/Groovy-Eclipse+compiler+plugin+for+Maven
// "Setting up source folders / Do nothing") we must copy *.groovy files as well
// reason: 'src/main/java' (or 'src/test/java') will be redirected to 'target/clover/src-instrumented'
// (or 'target/clover/src-test-instrumented') and Groovy compiler must be able to find these groovy sources
//
// 2) however we shall not copy groovy files from 'src/(main|test)/groovy' because these source roots are not
// being redirected to 'target/clover/src-(test-)instrumented'; furthermore groovy-eclipse-plugin has
// 'src/(main|test)/groovy' location hardcoded, so copying files would end up with 'duplicate class' build error
final Map groovyFilesToInstrument = scanner.getSourceFilesToInstrument(LanguageFileExtensionFilter.GROOVY_LANGUAGE, true);
// copy groovy files
if (!groovyFilesToInstrument.isEmpty()) {
copyExcludedFiles(groovyFilesToInstrument, outputSourceDirectory);
}
// We need to copy excluded files too as otherwise they won't be in the new Clover source directory and
// thus won't be compiled by the compile plugin. This will lead to compilation errors if any other
// file depends on any of these excluded files.
if (configuration.isCopyExcludedFiles()) {
final Map explicitlyExcludedFiles = scanner.getExcludedFiles();
// 'src/(main|test)/groovy' is already filtered-out in getExcludedFiles()
copyExcludedFiles(explicitlyExcludedFiles, outputSourceDirectory);
}
}
public String redirectSourceDirectories() {
return redirectSourceDirectories(outputSourceDirectory);
}
protected abstract CloverSourceScanner getSourceScanner();
protected abstract String getSourceDirectory();
protected abstract void setSourceDirectory(final String targetDirectory);
protected abstract List getCompileSourceRoots();
protected abstract void addCompileSourceRoot(final String sourceRoot);
protected abstract boolean isGeneratedSourcesDirectory(final String sourceRoot);
private String redirectSourceDirectories(final String targetDirectory) {
final String oldSourceDirectory = getSourceDirectory();
if (new File(oldSourceDirectory).exists()) {
setSourceDirectory(targetDirectory);
}
getConfiguration().getLog().debug("Clover " + getSourceType() + " source directories before change:");
logSourceDirectories();
// Maven2 limitation: changing the source directory doesn't change the compile source roots
// See http://jira.codehaus.org/browse/MNG-1945
final List sourceRoots = new ArrayList(getCompileSourceRoots());
// Clean all source roots to add them again in order to keep the same original order of source roots.
getCompileSourceRoots().removeAll(sourceRoots);
final CloverSourceScanner scanner = getSourceScanner();
for (final String sourceRoot : sourceRoots) {
// if includeAllSourceRoots=true then all source roots will be redirected to the location of instrumented sources
// if includeAllSourceRoots=false then we don't redirect generated source roots
boolean needsRedirection = getConfiguration().isIncludesAllSourceRoots() ||
!isGeneratedSourcesDirectory(sourceRoot);
// a) if it's a Java directory then use location of instrumented sources instead of the original source
// root (e.g. 'src/main/java' -> 'target/clover/src-instrumented')
// b) if it's a Groovy directory then don't change the location because we don't instrument Groovy on
// a source level, so the Clover's instrumented folder is empty; Groovy files will be instrumented
// during compilation on the AST level (e.g. 'src/main/groovy' -> 'src/main/groovy')
if (scanner.isSourceRootForLanguage(sourceRoot, Language.Builtin.GROOVY)) {
addCompileSourceRoot(sourceRoot);
} else {
addCompileSourceRoot(needsRedirection ? getSourceDirectory() : sourceRoot);
}
}
getConfiguration().getLog().debug("Clover " + getSourceType() + " source directories after change:");
logSourceDirectories();
return oldSourceDirectory;
}
private void logSourceDirectories() {
if (getConfiguration().getLog().isDebugEnabled()) {
for (String sourceRoot : getCompileSourceRoots()) {
getConfiguration().getLog().debug("[Clover] source root [" + sourceRoot + "]");
}
}
}
/**
* Copy all files that have been excluded by the user (using the excludes configuration property). This is required
* as otherwise the excluded files won't be in the new Clover source directory and thus won't be compiled by the
* compile plugin. This will lead to compilation errors if any other Java file depends on any of them.
*
* @throws MojoExecutionException if a failure happens during the copy
*/
private void copyExcludedFiles(final Map excludedFiles, final String targetDirectory) throws MojoExecutionException {
for (String sourceRoot : excludedFiles.keySet()) {
final String[] filesInSourceRoot = excludedFiles.get(sourceRoot);
for (String fileName : filesInSourceRoot) {
final File srcFile = new File(sourceRoot, fileName);
try {
configuration.getLog().debug("Copying excluded file: " + srcFile.getAbsolutePath() + " to " + targetDirectory);
FileUtils.copyFile(srcFile, new File(targetDirectory,
srcFile.getPath().substring(sourceRoot.length())));
} catch (IOException e) {
throw new MojoExecutionException("Failed to copy excluded file [" + srcFile + "] to ["
+ targetDirectory + "]", e);
}
}
}
}
private void instrumentSources(final Map filesToInstrument, final String outputDir) throws MojoExecutionException {
Logger.setInstance(new MvnLogger(configuration.getLog()));
// only make dirs when there is src to instrument. see CLMVN-118
new File(outputDir).mkdirs();
int result = CloverInstr.mainImpl(createCliArgs(filesToInstrument, outputDir));
if (result != 0) {
throw new MojoExecutionException("Clover has failed to instrument the source files "
+ "in the [" + outputDir + "] directory");
}
}
/**
* @return the CLI args to be passed to CloverInstr
*/
private String[] createCliArgs(final Map filesToInstrument, final String outputDir) throws MojoExecutionException {
final List parameters = new ArrayList();
parameters.add("-p");
parameters.add(getConfiguration().getFlushPolicy());
parameters.add("-f");
parameters.add("" + getConfiguration().getFlushInterval());
parameters.add("-i");
parameters.add(getConfiguration().resolveCloverDatabase());
parameters.add("-d");
parameters.add(outputDir);
if (getConfiguration().getLog().isDebugEnabled()) {
parameters.add("-v");
}
if (getConfiguration().getDistributedCoverage() != null && getConfiguration().getDistributedCoverage().isEnabled()) {
parameters.add("--distributedCoverage");
parameters.add(getConfiguration().getDistributedCoverage().toString());
}
final String javaLevel = getConfiguration().getJdk();
if (javaLevel != null) {
if (javaLevel.matches("1\\.[345678]")) {
parameters.add("--source");
parameters.add(javaLevel);
} else {
throw new MojoExecutionException("Unsupported java language level version [" + javaLevel
+ "]. Valid values are [1.3], [1.4], [1.5], [1.6], [1.7] and [1.8]");
}
}
if (!getConfiguration().isUseFullyQualifiedJavaLang()) {
parameters.add("--dontFullyQualifyJavaLang");
}
if (getConfiguration().getEncoding() != null) {
parameters.add("--encoding");
parameters.add(getConfiguration().getEncoding());
} else if (getConfiguration().getProject().getProperties().get(PROP_PROJECT_BUILD_SOURCEENCODING) != null) {
parameters.add("--encoding");
parameters.add(getConfiguration().getProject().getProperties().get(PROP_PROJECT_BUILD_SOURCEENCODING).toString());
}
if (getConfiguration().getInstrumentation() != null) {
parameters.add("--instrlevel");
parameters.add(getConfiguration().getInstrumentation());
}
if (getConfiguration().getInstrumentLambda() != null) {
parameters.add("--instrlambda");
parameters.add(getConfiguration().getInstrumentLambda());
}
for (final String srcDir : filesToInstrument.keySet()) {
final String[] filesInSourceRoot = filesToInstrument.get(srcDir);
for (String s : filesInSourceRoot) {
File file = new File(srcDir, s);
parameters.add(file.getPath());
}
}
// custom contexts
addCustomContexts(parameters, getConfiguration().getMethodContexts().entrySet(), "-mc");
addCustomContexts(parameters, getConfiguration().getStatementContexts().entrySet(), "-sc");
// Log parameters
if (getConfiguration().getLog().isDebugEnabled()) {
getConfiguration().getLog().debug("Parameter list being passed to Clover CLI:");
for (String param : parameters) {
getConfiguration().getLog().debug(" parameter = [" + param + "]");
}
}
return Iterables.toArray(parameters, String.class);
}
private void addCustomContexts(final List parameters, final Set> contexts, final String flag) {
for (final Map.Entry entry : contexts) {
parameters.add(flag);
parameters.add(entry.getKey() + "=" + entry.getValue());
}
}
protected abstract String getSourceType();
}