| /******************************************************************************* |
| * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Evgeny Mandrikov - initial API and implementation |
| * |
| *******************************************************************************/ |
| package org.jacoco.maven; |
| |
| import java.io.File; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| import org.apache.maven.artifact.Artifact; |
| import org.apache.maven.plugins.annotations.Parameter; |
| import org.codehaus.plexus.util.StringUtils; |
| import org.jacoco.core.runtime.AgentOptions; |
| |
| /** |
| * Base class for preparing a property pointing to the JaCoCo runtime agent that |
| * can be passed as a VM argument to the application under test. |
| */ |
| public abstract class AbstractAgentMojo extends AbstractJacocoMojo { |
| |
| /** |
| * Name of the JaCoCo Agent artifact. |
| */ |
| static final String AGENT_ARTIFACT_NAME = "org.jacoco:org.jacoco.agent"; |
| /** |
| * Name of the property used in maven-osgi-test-plugin. |
| */ |
| static final String TYCHO_ARG_LINE = "tycho.testArgLine"; |
| /** |
| * Name of the property used in maven-surefire-plugin. |
| */ |
| static final String SUREFIRE_ARG_LINE = "argLine"; |
| /** |
| * Map of plugin artifacts. |
| */ |
| @Parameter(property = "plugin.artifactMap", required = true, readonly = true) |
| Map<String, Artifact> pluginArtifactMap; |
| /** |
| * Allows to specify property which will contains settings for JaCoCo Agent. |
| * If not specified, then "argLine" would be used for "jar" packaging and |
| * "tycho.testArgLine" for "eclipse-test-plugin". |
| */ |
| @Parameter(property = "jacoco.propertyName") |
| String propertyName; |
| /** |
| * If set to true and the execution data file already exists, coverage data |
| * is appended to the existing file. If set to false, an existing execution |
| * data file will be replaced. |
| */ |
| @Parameter(property = "jacoco.append") |
| Boolean append; |
| /** |
| * A list of class loader names, that should be excluded from execution |
| * analysis. The list entries are separated by a colon (:) and may use |
| * wildcard characters (* and ?). This option might be required in case of |
| * special frameworks that conflict with JaCoCo code instrumentation, in |
| * particular class loaders that do not have access to the Java runtime |
| * classes. |
| */ |
| @Parameter(property = "jacoco.exclClassLoaders") |
| String exclClassLoaders; |
| /** |
| * Specifies whether also classes from the bootstrap classloader should be |
| * instrumented. Use this feature with caution, it needs heavy |
| * includes/excludes tuning. |
| */ |
| @Parameter(property = "jacoco.inclBootstrapClasses") |
| Boolean inclBootstrapClasses; |
| /** |
| * Specifies whether classes without source location should be instrumented. |
| */ |
| @Parameter(property = "jacoco.inclNoLocationClasses") |
| Boolean inclNoLocationClasses; |
| /** |
| * A session identifier that is written with the execution data. Without |
| * this parameter a random identifier is created by the agent. |
| */ |
| @Parameter(property = "jacoco.sessionId") |
| String sessionId; |
| /** |
| * If set to true coverage data will be written on VM shutdown. |
| */ |
| @Parameter(property = "jacoco.dumpOnExit") |
| Boolean dumpOnExit; |
| /** |
| * Output method to use for writing coverage data. Valid options are: |
| * <ul> |
| * <li>file: At VM termination execution data is written to a file.</li> |
| * <li>tcpserver: The agent listens for incoming connections on the TCP port |
| * specified by the {@link #address} and {@link #port}. Execution data is |
| * written to this TCP connection.</li> |
| * <li>tcpclient: At startup the agent connects to the TCP port specified by |
| * the {@link #address} and {@link #port}. Execution data is written to this |
| * TCP connection.</li> |
| * <li>none: Do not produce any output.</li> |
| * </ul> |
| */ |
| @Parameter(property = "jacoco.output") |
| String output; |
| /** |
| * IP address or hostname to bind to when the output method is tcpserver or |
| * connect to when the output method is tcpclient. In tcpserver mode the |
| * value "*" causes the agent to accept connections on any local address. |
| */ |
| @Parameter(property = "jacoco.address") |
| String address; |
| /** |
| * Port to bind to when the output method is tcpserver or connect to when |
| * the output method is tcpclient. In tcpserver mode the port must be |
| * available, which means that if multiple JaCoCo agents should run on the |
| * same machine, different ports have to be specified. |
| */ |
| @Parameter(property = "jacoco.port") |
| Integer port; |
| /** |
| * If a directory is specified for this parameter the JaCoCo agent dumps all |
| * class files it processes to the given location. This can be useful for |
| * debugging purposes or in case of dynamically created classes for example |
| * when scripting engines are used. |
| */ |
| @Parameter(property = "jacoco.classDumpDir") |
| File classDumpDir; |
| /** |
| * If set to true the agent exposes functionality via JMX. |
| */ |
| @Parameter(property = "jacoco.jmx") |
| Boolean jmx; |
| |
| @Override |
| public void executeMojo() { |
| final String name = getEffectivePropertyName(); |
| final Properties projectProperties = getProject().getProperties(); |
| final String oldValue = projectProperties.getProperty(name); |
| final String newValue = createAgentOptions().prependVMArguments( |
| oldValue, getAgentJarFile()); |
| getLog().info(name + " set to " + newValue); |
| projectProperties.setProperty(name, newValue); |
| } |
| |
| @Override |
| protected void skipMojo() { |
| final String name = getEffectivePropertyName(); |
| final Properties projectProperties = getProject().getProperties(); |
| final String oldValue = projectProperties.getProperty(name); |
| if (oldValue == null) { |
| getLog().info(name + " set to empty"); |
| projectProperties.setProperty(name, ""); |
| } |
| } |
| |
| File getAgentJarFile() { |
| final Artifact jacocoAgentArtifact = pluginArtifactMap |
| .get(AGENT_ARTIFACT_NAME); |
| return jacocoAgentArtifact.getFile(); |
| } |
| |
| AgentOptions createAgentOptions() { |
| final AgentOptions agentOptions = new AgentOptions(); |
| agentOptions.setDestfile(getDestFile().getAbsolutePath()); |
| if (append != null) { |
| agentOptions.setAppend(append.booleanValue()); |
| } |
| if (getIncludes() != null && !getIncludes().isEmpty()) { |
| final String agentIncludes = StringUtils.join(getIncludes() |
| .iterator(), ":"); |
| agentOptions.setIncludes(agentIncludes); |
| } |
| if (getExcludes() != null && !getExcludes().isEmpty()) { |
| final String agentExcludes = StringUtils.join(getExcludes() |
| .iterator(), ":"); |
| agentOptions.setExcludes(agentExcludes); |
| } |
| if (exclClassLoaders != null) { |
| agentOptions.setExclClassloader(exclClassLoaders); |
| } |
| if (inclBootstrapClasses != null) { |
| agentOptions.setInclBootstrapClasses(inclBootstrapClasses |
| .booleanValue()); |
| } |
| if (inclNoLocationClasses != null) { |
| agentOptions.setInclNoLocationClasses(inclNoLocationClasses |
| .booleanValue()); |
| } |
| if (sessionId != null) { |
| agentOptions.setSessionId(sessionId); |
| } |
| if (dumpOnExit != null) { |
| agentOptions.setDumpOnExit(dumpOnExit.booleanValue()); |
| } |
| if (output != null) { |
| agentOptions.setOutput(output); |
| } |
| if (address != null) { |
| agentOptions.setAddress(address); |
| } |
| if (port != null) { |
| agentOptions.setPort(port.intValue()); |
| } |
| if (classDumpDir != null) { |
| agentOptions.setClassDumpDir(classDumpDir.getAbsolutePath()); |
| } |
| if (jmx != null) { |
| agentOptions.setJmx(jmx.booleanValue()); |
| } |
| return agentOptions; |
| } |
| |
| String getEffectivePropertyName() { |
| if (isPropertyNameSpecified()) { |
| return propertyName; |
| } |
| if (isEclipseTestPluginPackaging()) { |
| return TYCHO_ARG_LINE; |
| } |
| return SUREFIRE_ARG_LINE; |
| } |
| |
| boolean isPropertyNameSpecified() { |
| return propertyName != null && !"".equals(propertyName); |
| } |
| |
| boolean isEclipseTestPluginPackaging() { |
| return "eclipse-test-plugin".equals(getProject().getPackaging()); |
| } |
| |
| /** |
| * @return the destFile |
| */ |
| abstract File getDestFile(); |
| |
| } |