[MINVOKER-218] Change package to o.a.m.plugins

git-svn-id: https://svn.apache.org/repos/asf/maven/plugins/trunk@1795243 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/it/local-repo-url/src/it/project/postbuild.groovy b/src/it/local-repo-url/src/it/project/postbuild.groovy
index 08e0795..6b8ec74 100644
--- a/src/it/local-repo-url/src/it/project/postbuild.groovy
+++ b/src/it/local-repo-url/src/it/project/postbuild.groovy
@@ -24,7 +24,7 @@
 assert interpolatedSettings.isFile()

 

 def filename = new File( basedir, "../../../../../local-repo" ).canonicalPath

-// Convert URL, see org.apache.maven.plugin.invoker.AbstractInvokerMojo.toUrl(String)

+// Convert URL, see org.apache.maven.plugins.invoker.AbstractInvokerMojo.toUrl(String)

 String url = "file://" + new File(  filename  ).toURI().path

 if ( url.endsWith( "/" ) )

 {

diff --git a/src/main/java/org/apache/maven/plugin/invoker/AbstractInvokerMojo.java b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
similarity index 99%
rename from src/main/java/org/apache/maven/plugin/invoker/AbstractInvokerMojo.java
rename to src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
index dfe85fe..bdd1416 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/AbstractInvokerMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/AbstractInvokerMojo.java
@@ -1,2553 +1,2553 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.Writer;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-import java.util.StringTokenizer;
-import java.util.TreeSet;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Profile;
-import org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecution;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.invoker.model.BuildJob;
-import org.apache.maven.plugin.invoker.model.io.xpp3.BuildJobXpp3Writer;
-import org.apache.maven.plugins.annotations.Component;
-import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.settings.Settings;
-import org.apache.maven.settings.SettingsUtils;
-import org.apache.maven.settings.TrackableBase;
-import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
-import org.apache.maven.settings.building.SettingsBuilder;
-import org.apache.maven.settings.building.SettingsBuildingException;
-import org.apache.maven.settings.building.SettingsBuildingRequest;
-import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
-import org.apache.maven.shared.invoker.CommandLineConfigurationException;
-import org.apache.maven.shared.invoker.DefaultInvocationRequest;
-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.MavenCommandLineBuilder;
-import org.apache.maven.shared.invoker.MavenInvocationException;
-import org.apache.maven.shared.scriptinterpreter.RunErrorException;
-import org.apache.maven.shared.scriptinterpreter.RunFailureException;
-import org.apache.maven.shared.scriptinterpreter.ScriptRunner;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
-import org.codehaus.plexus.interpolation.InterpolationException;
-import org.codehaus.plexus.interpolation.Interpolator;
-import org.codehaus.plexus.interpolation.MapBasedValueSource;
-import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
-import org.codehaus.plexus.util.DirectoryScanner;
-import org.codehaus.plexus.util.FileUtils;
-import org.codehaus.plexus.util.IOUtil;
-import org.codehaus.plexus.util.InterpolationFilterReader;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.ReflectionUtils;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.WriterFactory;
-import org.codehaus.plexus.util.cli.CommandLineException;
-import org.codehaus.plexus.util.cli.CommandLineUtils;
-import org.codehaus.plexus.util.cli.Commandline;
-import org.codehaus.plexus.util.cli.StreamConsumer;
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
-
-/**
- * Provides common code for mojos invoking sub builds.
- *
- * @author Stephen Connolly
- * @since 15-Aug-2009 09:09:29
- */
-public abstract class AbstractInvokerMojo
-    extends AbstractMojo
-{
-    /**
-     * The zero-based column index where to print the invoker result.
-     */
-    private static final int RESULT_COLUMN = 60;
-
-    /**
-     * Flag used to suppress certain invocations. This is useful in tailoring the build using profiles.
-     *
-     * @since 1.1
-     */
-    @Parameter( property = "invoker.skip", defaultValue = "false" )
-    private boolean skipInvocation;
-
-    /**
-     * Flag used to suppress the summary output notifying of successes and failures. If set to <code>true</code>, the
-     * only indication of the build's success or failure will be the effect it has on the main build (if it fails, the
-     * main build should fail as well). If {@link #streamLogs} is enabled, the sub-build summary will also provide an
-     * indication.
-     */
-    @Parameter( defaultValue = "false" )
-    protected boolean suppressSummaries;
-
-    /**
-     * Flag used to determine whether the build logs should be output to the normal mojo log.
-     */
-    @Parameter( property = "invoker.streamLogs", defaultValue = "false" )
-    private boolean streamLogs;
-
-    /**
-     * The local repository for caching artifacts. It is strongly recommended to specify a path to an isolated
-     * repository like <code>${project.build.directory}/it-repo</code>. Otherwise, your ordinary local repository will
-     * be used, potentially soiling it with broken artifacts.
-     */
-    @Parameter( property = "invoker.localRepositoryPath", defaultValue = "${settings.localRepository}" )
-    private File localRepositoryPath;
-
-    /**
-     * Directory to search for integration tests.
-     */
-    @Parameter( property = "invoker.projectsDirectory", defaultValue = "${basedir}/src/it/" )
-    private File projectsDirectory;
-
-    /**
-     * Base directory where all build reports are written to. Every execution of an integration test will produce an XML
-     * file which contains the information about success or failure of that particular build job. The format of the
-     * resulting XML file is documented in the given <a href="./build-job.html">build-job</a> reference.
-     *
-     * @since 1.4
-     */
-    @Parameter( property = "invoker.reportsDirectory", defaultValue = "${project.build.directory}/invoker-reports" )
-    private File reportsDirectory;
-
-    /**
-     * A flag to disable the generation of build reports.
-     *
-     * @since 1.4
-     */
-    @Parameter( property = "invoker.disableReports", defaultValue = "false" )
-    private boolean disableReports;
-
-    /**
-     * Directory to which projects should be cloned prior to execution. If not specified, each integration test will be
-     * run in the directory in which the corresponding IT POM was found. In this case, you most likely want to configure
-     * your SCM to ignore <code>target</code> and <code>build.log</code> in the test's base directory.
-     *
-     * @since 1.1
-     */
-    @Parameter
-    private File cloneProjectsTo;
-
-    // CHECKSTYLE_OFF: LineLength
-    /**
-     * Some files are normally excluded when copying the IT projects from the directory specified by the parameter
-     * projectsDirectory to the directory given by cloneProjectsTo (e.g. <code>.svn</code>, <code>CVS</code>,
-     * <code>*~</code>, etc: see <a href=
-     * "https://codehaus-plexus.github.io/plexus-utils/apidocs/org/codehaus/plexus/util/AbstractScanner.html#DEFAULTEXCLUDES">
-     * reference</a> for full list). Setting this parameter to <code>true</code> will cause all files to be copied to
-     * the <code>cloneProjectsTo</code> directory.
-     *
-     * @since 1.2
-     */
-    @Parameter( defaultValue = "false" )
-    private boolean cloneAllFiles;
-    // CHECKSTYLE_ON: LineLength
-
-    /**
-     * Ensure the {@link #cloneProjectsTo} directory is not polluted with files from earlier invoker runs.
-     *
-     * @since 1.6
-     */
-    @Parameter( defaultValue = "false" )
-    private boolean cloneClean;
-
-    /**
-     * A single POM to build, skipping any scanning parameters and behavior.
-     */
-    @Parameter( property = "invoker.pom" )
-    private File pom;
-
-    /**
-     * Include patterns for searching the integration test directory for projects. This parameter is meant to be set
-     * from the POM. If this parameter is not set, the plugin will search for all <code>pom.xml</code> files one
-     * directory below {@link #projectsDirectory} (i.e. <code>*&#47;pom.xml</code>).<br>
-     * <br>
-     * Starting with version 1.3, mere directories can also be matched by these patterns. For example, the include
-     * pattern <code>*</code> will run Maven builds on all immediate sub directories of {@link #projectsDirectory},
-     * regardless if they contain a <code>pom.xml</code>. This allows to perform builds that need/should not depend on
-     * the existence of a POM.
-     */
-    @Parameter
-    private List<String> pomIncludes = Collections.singletonList( "*/pom.xml" );
-
-    /**
-     * Exclude patterns for searching the integration test directory. This parameter is meant to be set from the POM. By
-     * default, no POM files are excluded. For the convenience of using an include pattern like <code>*</code>, the
-     * custom settings file specified by the parameter {@link #settingsFile} will always be excluded automatically.
-     */
-    @Parameter
-    private List<String> pomExcludes = Collections.emptyList();
-
-    /**
-     * Include patterns for searching the projects directory for projects that need to be run before the other projects.
-     * This parameter allows to declare projects that perform setup tasks like installing utility artifacts into the
-     * local repository. Projects matched by these patterns are implicitly excluded from the scan for ordinary projects.
-     * Also, the exclusions defined by the parameter {@link #pomExcludes} apply to the setup projects, too. Default
-     * value is: <code>setup*&#47;pom.xml</code>.
-     *
-     * @since 1.3
-     */
-    @Parameter
-    private List<String> setupIncludes = Collections.singletonList( "setup*/pom.xml" );
-
-    /**
-     * The list of goals to execute on each project. Default value is: <code>package</code>.
-     */
-    @Parameter
-    private List<String> goals = Collections.singletonList( "package" );
-
-    /**
-     */
-    @Component
-    private Invoker invoker;
-
-    @Component
-    private SettingsBuilder settingsBuilder;
-
-    /**
-     * Relative path of a selector script to run prior in order to decide if the build should be executed. This script
-     * may be written with either BeanShell or Groovy. If the file extension is omitted (e.g. <code>selector</code>),
-     * the plugin searches for the file by trying out the well-known extensions <code>.bsh</code> and
-     * <code>.groovy</code>. If this script exists for a particular project but returns any non-null value different
-     * from <code>true</code>, the corresponding build is flagged as skipped. In this case, none of the pre-build hook
-     * script, Maven nor the post-build hook script will be invoked. If this script throws an exception, the
-     * corresponding build is flagged as in error, and none of the pre-build hook script, Maven not the post-build hook
-     * script will be invoked.
-     *
-     * @since 1.5
-     */
-    @Parameter( property = "invoker.selectorScript", defaultValue = "selector" )
-    private String selectorScript;
-
-    /**
-     * Relative path of a pre-build hook script to run prior to executing the build. This script may be written with
-     * either BeanShell or Groovy (since 1.3). If the file extension is omitted (e.g. <code>prebuild</code>), the plugin
-     * searches for the file by trying out the well-known extensions <code>.bsh</code> and <code>.groovy</code>. If this
-     * script exists for a particular project but returns any non-null value different from <code>true</code> or throws
-     * an exception, the corresponding build is flagged as a failure. In this case, neither Maven nor the post-build
-     * hook script will be invoked.
-     */
-    @Parameter( property = "invoker.preBuildHookScript", defaultValue = "prebuild" )
-    private String preBuildHookScript;
-
-    /**
-     * Relative path of a cleanup/verification hook script to run after executing the build. This script may be written
-     * with either BeanShell or Groovy (since 1.3). If the file extension is omitted (e.g. <code>verify</code>), the
-     * plugin searches for the file by trying out the well-known extensions <code>.bsh</code> and <code>.groovy</code>.
-     * If this script exists for a particular project but returns any non-null value different from <code>true</code> or
-     * throws an exception, the corresponding build is flagged as a failure.
-     */
-    @Parameter( property = "invoker.postBuildHookScript", defaultValue = "postbuild" )
-    private String postBuildHookScript;
-
-    /**
-     * Location of a properties file that defines CLI properties for the test.
-     */
-    @Parameter( property = "invoker.testPropertiesFile", defaultValue = "test.properties" )
-    private String testPropertiesFile;
-
-    /**
-     * Common set of properties to pass in on each project's command line, via -D parameters.
-     *
-     * @since 1.1
-     */
-    @Parameter
-    private Map<String, String> properties;
-
-    /**
-     * Whether to show errors in the build output.
-     */
-    @Parameter( property = "invoker.showErrors", defaultValue = "false" )
-    private boolean showErrors;
-
-    /**
-     * Whether to show debug statements in the build output.
-     */
-    @Parameter( property = "invoker.debug", defaultValue = "false" )
-    private boolean debug;
-
-    /**
-     * Suppress logging to the <code>build.log</code> file.
-     */
-    @Parameter( property = "invoker.noLog", defaultValue = "false" )
-    private boolean noLog;
-
-    /**
-     * List of profile identifiers to explicitly trigger in the build.
-     *
-     * @since 1.1
-     */
-    @Parameter
-    private List<String> profiles;
-
-    /**
-     * A list of additional properties which will be used to filter tokens in POMs and goal files.
-     *
-     * @since 1.3
-     */
-    @Parameter
-    private Map<String, String> filterProperties;
-
-    /**
-     * The Maven Project Object
-     *
-     * @since 1.1
-     */
-    @Parameter( defaultValue = "${project}", readonly = true, required = true )
-    private MavenProject project;
-
-    @Parameter( defaultValue = "${mojoExecution}", readonly = true, required = true )
-    private MojoExecution mojoExecution;
-
-    /**
-     * A comma separated list of projectname patterns to run. Specify this parameter to run individual tests by file
-     * name, overriding the {@link #setupIncludes}, {@link #pomIncludes} and {@link #pomExcludes} parameters. Each
-     * pattern you specify here will be used to create an include/exclude pattern formatted like
-     * <code>${projectsDirectory}/<i>pattern</i></code>. To exclude a test, prefix the pattern with a '<code>!</code>'.
-     * So you can just type <nobr><code>-Dinvoker.test=SimpleTest,Comp*Test,!Compare*</code></nobr> to run builds in
-     * <code>${projectsDirectory}/SimpleTest</code> and <code>${projectsDirectory}/ComplexTest</code>, but not
-     * <code>${projectsDirectory}/CompareTest</code>
-     *
-     * @since 1.1 (exclusion since 1.8)
-     */
-    @Parameter( property = "invoker.test" )
-    private String invokerTest;
-
-    /**
-     * Path to an alternate <code>settings.xml</code> to use for Maven invocation with all ITs. Note that the
-     * <code>&lt;localRepository&gt;</code> element of this settings file is always ignored, i.e. the path given by the
-     * parameter {@link #localRepositoryPath} is dominant.
-     *
-     * @since 1.2
-     */
-    @Parameter( property = "invoker.settingsFile" )
-    private File settingsFile;
-
-    /**
-     * The <code>MAVEN_OPTS</code> environment variable to use when invoking Maven. This value can be overridden for
-     * individual integration tests by using {@link #invokerPropertiesFile}.
-     *
-     * @since 1.2
-     */
-    @Parameter( property = "invoker.mavenOpts" )
-    private String mavenOpts;
-
-    /**
-     * The home directory of the Maven installation to use for the forked builds. Defaults to the current Maven
-     * installation.
-     *
-     * @since 1.3
-     */
-    @Parameter( property = "invoker.mavenHome" )
-    private File mavenHome;
-
-    /**
-     * mavenExecutable can either be a file relative to <code>${maven.home}/bin/</code> or an absolute file.
-     *
-     * @since 1.8
-     * @see Invoker#setMavenExecutable(File)
-     */
-    @Parameter( property = "invoker.mavenExecutable" )
-    private String mavenExecutable;
-
-    /**
-     * The <code>JAVA_HOME</code> environment variable to use for forked Maven invocations. Defaults to the current Java
-     * home directory.
-     *
-     * @since 1.3
-     */
-    @Parameter( property = "invoker.javaHome" )
-    private File javaHome;
-
-    /**
-     * The file encoding for the pre-/post-build scripts and the list files for goals and profiles.
-     *
-     * @since 1.2
-     */
-    @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
-    private String encoding;
-
-    /**
-     * The current user system settings for use in Maven.
-     *
-     * @since 1.2
-     */
-    @Parameter( defaultValue = "${settings}", readonly = true, required = true )
-    private Settings settings;
-
-    /**
-     * A flag whether the test class path of the project under test should be included in the class path of the
-     * pre-/post-build scripts. If set to <code>false</code>, the class path of script interpreter consists only of the
-     * <a href="dependencies.html">runtime dependencies</a> of the Maven Invoker Plugin. If set the <code>true</code>,
-     * the project's test class path will be prepended to the interpreter class path. Among others, this feature allows
-     * the scripts to access utility classes from the test sources of your project.
-     *
-     * @since 1.2
-     */
-    @Parameter( property = "invoker.addTestClassPath", defaultValue = "false" )
-    private boolean addTestClassPath;
-
-    /**
-     * The test class path of the project under test.
-     */
-    @Parameter( defaultValue = "${project.testClasspathElements}", readonly = true )
-    private List<String> testClassPath;
-
-    /**
-     * The name of an optional project-specific file that contains properties used to specify settings for an individual
-     * Maven invocation. Any property present in the file will override the corresponding setting from the plugin
-     * configuration. The values of the properties are filtered and may use expressions like
-     * <code>${project.version}</code> to reference project properties or values from the parameter
-     * {@link #filterProperties}. The snippet below describes the supported properties:
-     * <p/>
-     *
-     * <pre>
-     * # A comma or space separated list of goals/phases to execute, may
-     * # specify an empty list to execute the default goal of the IT project.
-     * # Environment variables used by maven plugins can be added here
-     * invoker.goals = clean install -Dplugin.variable=value
-     *
-     * # Or you can give things like this if you need.
-     * invoker.goals = -T2 clean verify
-     *
-     * # Optionally, a list of goals to run during further invocations of Maven
-     * invoker.goals.2 = ${project.groupId}:${project.artifactId}:${project.version}:run
-     *
-     * # A comma or space separated list of profiles to activate
-     * invoker.profiles = its,jdk15
-     *
-     * # The path to an alternative POM or base directory to invoke Maven on, defaults to the
-     * # project that was originally specified in the plugin configuration
-     * # Since plugin version 1.4
-     * invoker.project = sub-module
-     *
-     * # The value for the environment variable MAVEN_OPTS
-     * invoker.mavenOpts = -Dfile.encoding=UTF-16 -Xms32m -Xmx256m
-     *
-     * # Possible values are &quot;fail-fast&quot; (default), &quot;fail-at-end&quot; and &quot;fail-never&quot;
-     * invoker.failureBehavior = fail-never
-     *
-     * # The expected result of the build, possible values are &quot;success&quot; (default) and &quot;failure&quot;
-     * invoker.buildResult = failure
-     *
-     * # A boolean value controlling the aggregator mode of Maven, defaults to &quot;false&quot;
-     * invoker.nonRecursive = true
-     *
-     * # A boolean value controlling the network behavior of Maven, defaults to &quot;false&quot;
-     * # Since plugin version 1.4
-     * invoker.offline = true
-     *
-     * # The path to the properties file from which to load system properties, defaults to the
-     * # filename given by the plugin parameter testPropertiesFile
-     * # Since plugin version 1.4
-     * invoker.systemPropertiesFile = test.properties
-     *
-     * # An optional human friendly name for this build job to be included in the build reports.
-     * # Since plugin version 1.4
-     * invoker.name = Test Build 01
-     *
-     * # An optional description for this build job to be included in the build reports.
-     * # Since plugin version 1.4
-     * invoker.description = Checks the support for build reports.
-     *
-     * # A comma separated list of JRE versions on which this build job should be run.
-     * # Since plugin version 1.4
-     * invoker.java.version = 1.4+, !1.4.1, 1.7-
-     * 
-     * # A comma separated list of OS families on which this build job should be run.
-     * # Since plugin version 1.4
-     * invoker.os.family = !windows, unix, mac
-     *
-     * # A comma separated list of Maven versions on which this build should be run.
-     * # Since plugin version 1.5
-     * invoker.maven.version = 2.0.10+, !2.1.0, !2.2.0
-     * 
-     * # For java.version, maven.version and os.family it is possible to define multiple selectors.
-     * # If one of the indexed selectors matches, the test is executed.
-     * # With the invoker.x.y equivalents you can specify global matchers.  
-     * selector.1.java.version = 1.8+
-     * selector.1.maven.version = 3.2.5+
-     * selector.1.os.family = !windows
-     * selector.2.maven.version = 3.0+
-     * selector.3.java.version = 9+
-     * 
-     * # A boolean value controlling the debug logging level of Maven, , defaults to &quot;false&quot;
-     * # Since plugin version 1.8
-     * invoker.debug = true
-     * </pre>
-     *
-     * @since 1.2
-     */
-    @Parameter( property = "invoker.invokerPropertiesFile", defaultValue = "invoker.properties" )
-    private String invokerPropertiesFile;
-
-    /**
-     * flag to enable show mvn version used for running its (cli option : -V,--show-version )
-     *
-     * @since 1.4
-     */
-    @Parameter( property = "invoker.showVersion", defaultValue = "false" )
-    private boolean showVersion;
-
-    /**
-     * number of threads for running tests in parallel. This will be the number of maven forked process in parallel.
-     *
-     * @since 1.6
-     */
-    @Parameter( property = "invoker.parallelThreads", defaultValue = "1" )
-    private int parallelThreads;
-
-    /**
-     * @since 1.6
-     */
-    @Parameter( property = "plugin.artifacts", required = true, readonly = true )
-    private List<Artifact> pluginArtifacts;
-
-    /**
-     * If enable and if you have a settings file configured for the execution, it will be merged with your user
-     * settings.
-     *
-     * @since 1.6
-     */
-    @Parameter( property = "invoker.mergeUserSettings", defaultValue = "false" )
-    private boolean mergeUserSettings;
-
-    /**
-     * Additional environment variables to set on the command line.
-     *
-     * @since 1.8
-     */
-    @Parameter
-    private Map<String, String> environmentVariables;
-
-    /**
-     * Additional variables for use in the hook scripts.
-     *
-     * @since 1.9
-     */
-    @Parameter
-    private Map<String, String> scriptVariables;
-
-    /**
-     * The scripter runner that is responsible to execute hook scripts.
-     */
-    private ScriptRunner scriptRunner;
-
-    /**
-     * A string used to prefix the file name of the filtered POMs in case the POMs couldn't be filtered in-place (i.e.
-     * the projects were not cloned to a temporary directory), can be <code>null</code>. This will be set to
-     * <code>null</code> if the POMs have already been filtered during cloning.
-     */
-    private String filteredPomPrefix = "interpolated-";
-
-    /**
-     * The format for elapsed build time.
-     */
-    private final DecimalFormat secFormat = new DecimalFormat( "(0.0 s)", new DecimalFormatSymbols( Locale.ENGLISH ) );
-
-    /**
-     * The version of Maven which is used to run the builds
-     */
-    private String actualMavenVersion;
-
-    /**
-     * Invokes Maven on the configured test projects.
-     *
-     * @throws org.apache.maven.plugin.MojoExecutionException If the goal encountered severe errors.
-     * @throws org.apache.maven.plugin.MojoFailureException If any of the Maven builds failed.
-     */
-    public void execute()
-        throws MojoExecutionException, MojoFailureException
-    {
-        if ( skipInvocation )
-        {
-            getLog().info( "Skipping invocation per configuration."
-                + " If this is incorrect, ensure the skipInvocation parameter is not set to true." );
-            return;
-        }
-
-        if ( StringUtils.isEmpty( encoding ) )
-        {
-            getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
-                + ", i.e. build is platform dependent!" );
-        }
-
-        // done it here to prevent issues with concurrent access in case of parallel run
-        if ( !disableReports )
-        {
-            setupReportsFolder();
-        }
-
-        BuildJob[] buildJobs;
-        if ( pom == null )
-        {
-            try
-            {
-                buildJobs = getBuildJobs();
-            }
-            catch ( final IOException e )
-            {
-                throw new MojoExecutionException( "Error retrieving POM list from includes, "
-                    + "excludes, and projects directory. Reason: " + e.getMessage(), e );
-            }
-        }
-        else
-        {
-            try
-            {
-                projectsDirectory = pom.getCanonicalFile().getParentFile();
-            }
-            catch ( IOException e )
-            {
-                throw new MojoExecutionException( "Failed to discover projectsDirectory from "
-                    + "pom File parameter. Reason: " + e.getMessage(), e );
-            }
-
-            buildJobs = new BuildJob[] { new BuildJob( pom.getName(), BuildJob.Type.NORMAL ) };
-        }
-
-        if ( ( buildJobs == null ) || ( buildJobs.length < 1 ) )
-        {
-            doFailIfNoProjects();
-
-            getLog().info( "No projects were selected for execution." );
-            return;
-        }
-
-        handleScriptRunnerWithScriptClassPath();
-
-        Collection<String> collectedProjects = new LinkedHashSet<String>();
-        for ( BuildJob buildJob : buildJobs )
-        {
-            collectProjects( projectsDirectory, buildJob.getProject(), collectedProjects, true );
-        }
-
-        File projectsDir = projectsDirectory;
-
-        if ( cloneProjectsTo != null )
-        {
-            cloneProjects( collectedProjects );
-            projectsDir = cloneProjectsTo;
-        }
-        else
-        {
-            getLog().warn( "Filtering of parent/child POMs is not supported without cloning the projects" );
-        }
-
-        // First run setup jobs.
-        BuildJob[] setupBuildJobs = null;
-        try
-        {
-            setupBuildJobs = getSetupBuildJobsFromFolders();
-        }
-        catch ( IOException e )
-        {
-            getLog().error( "Failure during scanning of folders.", e );
-            // TODO: Check shouldn't we fail in case of problems?
-        }
-
-        if ( setupBuildJobs != null )
-        {
-            // Run setup jobs in single thread
-            // mode.
-            //
-            // Some Idea about ordering?
-            getLog().info( "Running Setup Jobs" );
-            runBuilds( projectsDir, setupBuildJobs, 1 );
-        }
-
-        // Afterwards run all other jobs.
-        BuildJob[] nonSetupBuildJobs = getNonSetupJobs( buildJobs );
-        // We will run the non setup jobs with the configured
-        // parallelThreads number.
-        runBuilds( projectsDir, nonSetupBuildJobs, parallelThreads );
-
-        writeSummaryFile( nonSetupBuildJobs );
-
-        processResults( new InvokerSession( nonSetupBuildJobs ) );
-
-    }
-
-    /**
-     * This will create the necessary folders for the reports.
-     * 
-     * @throws MojoExecutionException in case of failure during creation of the reports folder.
-     */
-    private void setupReportsFolder()
-        throws MojoExecutionException
-    {
-        // If it exists from previous run...
-        if ( reportsDirectory.exists() )
-        {
-            try
-            {
-                FileUtils.deleteDirectory( reportsDirectory );
-            }
-            catch ( IOException e )
-            {
-                throw new MojoExecutionException( "Failure while trying to delete "
-                    + reportsDirectory.getAbsolutePath(), e );
-            }
-        }
-        if ( !reportsDirectory.mkdirs() )
-        {
-            throw new MojoExecutionException( "Failure while creating the " + reportsDirectory.getAbsolutePath() );
-        }
-    }
-
-    private BuildJob[] getNonSetupJobs( BuildJob[] buildJobs )
-    {
-        List<BuildJob> result = new LinkedList<BuildJob>();
-        for ( int i = 0; i < buildJobs.length; i++ )
-        {
-            if ( !buildJobs[i].getType().equals( BuildJob.Type.SETUP ) )
-            {
-                result.add( buildJobs[i] );
-            }
-        }
-        BuildJob[] buildNonSetupJobs = result.toArray( new BuildJob[result.size()] );
-        return buildNonSetupJobs;
-    }
-
-    private void handleScriptRunnerWithScriptClassPath()
-    {
-        final List<String> scriptClassPath;
-        if ( addTestClassPath )
-        {
-            scriptClassPath = new ArrayList<String>( testClassPath );
-            for ( Artifact pluginArtifact : pluginArtifacts )
-            {
-                scriptClassPath.remove( pluginArtifact.getFile().getAbsolutePath() );
-            }
-        }
-        else
-        {
-            scriptClassPath = null;
-        }
-        scriptRunner = new ScriptRunner( getLog() );
-        scriptRunner.setScriptEncoding( encoding );
-        scriptRunner.setGlobalVariable( "localRepositoryPath", localRepositoryPath );
-        if ( scriptVariables != null )
-        {
-            for ( Entry<String, String> entry : scriptVariables.entrySet() )
-            {
-                scriptRunner.setGlobalVariable( entry.getKey(), entry.getValue() );
-            }
-        }
-        scriptRunner.setClassPath( scriptClassPath );
-    }
-
-    private void writeSummaryFile( BuildJob[] buildJobs )
-        throws MojoExecutionException
-    {
-
-        File summaryReportFile = new File( reportsDirectory, "invoker-summary.txt" );
-
-        try
-        {
-            Writer writer = new BufferedWriter( new FileWriter( summaryReportFile ) );
-
-            for ( int i = 0; i < buildJobs.length; i++ )
-            {
-                BuildJob buildJob = buildJobs[i];
-                if ( !buildJob.getResult().equals( BuildJob.Result.SUCCESS ) )
-                {
-                    writer.append( buildJob.getResult() );
-                    writer.append( " [" );
-                    writer.append( buildJob.getProject() );
-                    writer.append( "] " );
-                    if ( buildJob.getFailureMessage() != null )
-                    {
-                        writer.append( " " );
-                        writer.append( buildJob.getFailureMessage() );
-                    }
-                    writer.append( "\n" );
-                }
-            }
-
-            writer.close();
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( "Failed to write summary report " + summaryReportFile, e );
-        }
-    }
-
-    protected void doFailIfNoProjects()
-        throws MojoFailureException
-    {
-        // should only be used during run and verify
-    }
-
-    /**
-     * Processes the results of invoking the build jobs.
-     *
-     * @param invokerSession The session with the build jobs, must not be <code>null</code>.
-     * @throws MojoFailureException If the mojo had failed as a result of invoking the build jobs.
-     * @since 1.4
-     */
-    abstract void processResults( InvokerSession invokerSession )
-        throws MojoFailureException;
-
-    /**
-     * Creates a new reader for the specified file, using the plugin's {@link #encoding} parameter.
-     *
-     * @param file The file to create a reader for, must not be <code>null</code>.
-     * @return The reader for the file, never <code>null</code>.
-     * @throws java.io.IOException If the specified file was not found or the configured encoding is not supported.
-     */
-    private Reader newReader( File file )
-        throws IOException
-    {
-        if ( StringUtils.isNotEmpty( encoding ) )
-        {
-            return ReaderFactory.newReader( file, encoding );
-        }
-        else
-        {
-            return ReaderFactory.newPlatformReader( file );
-        }
-    }
-
-    /**
-     * Collects all projects locally reachable from the specified project. The method will as such try to read the POM
-     * and recursively follow its parent/module elements.
-     *
-     * @param projectsDir The base directory of all projects, must not be <code>null</code>.
-     * @param projectPath The relative path of the current project, can denote either the POM or its base directory,
-     *            must not be <code>null</code>.
-     * @param projectPaths The set of already collected projects to add new projects to, must not be <code>null</code>.
-     *            This set will hold the relative paths to either a POM file or a project base directory.
-     * @param included A flag indicating whether the specified project has been explicitly included via the parameter
-     *            {@link #pomIncludes}. Such projects will always be added to the result set even if there is no
-     *            corresponding POM.
-     * @throws org.apache.maven.plugin.MojoExecutionException If the project tree could not be traversed.
-     */
-    private void collectProjects( File projectsDir, String projectPath, Collection<String> projectPaths,
-                                  boolean included )
-        throws MojoExecutionException
-    {
-        projectPath = projectPath.replace( '\\', '/' );
-        File pomFile = new File( projectsDir, projectPath );
-        if ( pomFile.isDirectory() )
-        {
-            pomFile = new File( pomFile, "pom.xml" );
-            if ( !pomFile.exists() )
-            {
-                if ( included )
-                {
-                    projectPaths.add( projectPath );
-                }
-                return;
-            }
-            if ( !projectPath.endsWith( "/" ) )
-            {
-                projectPath += '/';
-            }
-            projectPath += "pom.xml";
-        }
-        else if ( !pomFile.isFile() )
-        {
-            return;
-        }
-        if ( !projectPaths.add( projectPath ) )
-        {
-            return;
-        }
-        getLog().debug( "Collecting parent/child projects of " + projectPath );
-
-        Model model = PomUtils.loadPom( pomFile );
-
-        try
-        {
-            String projectsRoot = projectsDir.getCanonicalPath();
-            String projectDir = pomFile.getParent();
-
-            String parentPath = "../pom.xml";
-            if ( model.getParent() != null && StringUtils.isNotEmpty( model.getParent().getRelativePath() ) )
-            {
-                parentPath = model.getParent().getRelativePath();
-            }
-            String parent = relativizePath( new File( projectDir, parentPath ), projectsRoot );
-            if ( parent != null )
-            {
-                collectProjects( projectsDir, parent, projectPaths, false );
-            }
-
-            Collection<String> modulePaths = new LinkedHashSet<String>();
-
-            modulePaths.addAll( model.getModules() );
-
-            for ( Profile profile : model.getProfiles() )
-            {
-                modulePaths.addAll( profile.getModules() );
-            }
-
-            for ( String modulePath : modulePaths )
-            {
-                String module = relativizePath( new File( projectDir, modulePath ), projectsRoot );
-                if ( module != null )
-                {
-                    collectProjects( projectsDir, module, projectPaths, false );
-                }
-            }
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( "Failed to analyze POM: " + pomFile, e );
-        }
-    }
-
-    /**
-     * Copies the specified projects to the directory given by {@link #cloneProjectsTo}. A project may either be denoted
-     * by a path to a POM file or merely by a path to a base directory. During cloning, the POM files will be filtered.
-     *
-     * @param projectPaths The paths to the projects to clone, relative to the projects directory, must not be
-     *            <code>null</code> nor contain <code>null</code> elements.
-     * @throws org.apache.maven.plugin.MojoExecutionException If the the projects could not be copied/filtered.
-     */
-    private void cloneProjects( Collection<String> projectPaths )
-        throws MojoExecutionException
-    {
-        if ( !cloneProjectsTo.mkdirs() && cloneClean )
-        {
-            try
-            {
-                FileUtils.cleanDirectory( cloneProjectsTo );
-            }
-            catch ( IOException e )
-            {
-                throw new MojoExecutionException( "Could not clean the cloneProjectsTo directory. Reason: "
-                    + e.getMessage(), e );
-            }
-        }
-
-        // determine project directories to clone
-        Collection<String> dirs = new LinkedHashSet<String>();
-        for ( String projectPath : projectPaths )
-        {
-            if ( !new File( projectsDirectory, projectPath ).isDirectory() )
-            {
-                projectPath = getParentPath( projectPath );
-            }
-            dirs.add( projectPath );
-        }
-
-        boolean filter;
-
-        // clone project directories
-        try
-        {
-            filter = !cloneProjectsTo.getCanonicalFile().equals( projectsDirectory.getCanonicalFile() );
-
-            List<String> clonedSubpaths = new ArrayList<String>();
-
-            for ( String subpath : dirs )
-            {
-                // skip this project if its parent directory is also scheduled for cloning
-                if ( !".".equals( subpath ) && dirs.contains( getParentPath( subpath ) ) )
-                {
-                    continue;
-                }
-
-                // avoid copying subdirs that are already cloned.
-                if ( !alreadyCloned( subpath, clonedSubpaths ) )
-                {
-                    // avoid creating new files that point to dir/.
-                    if ( ".".equals( subpath ) )
-                    {
-                        String cloneSubdir = relativizePath( cloneProjectsTo, projectsDirectory.getCanonicalPath() );
-
-                        // avoid infinite recursion if the cloneTo path is a subdirectory.
-                        if ( cloneSubdir != null )
-                        {
-                            File temp = File.createTempFile( "pre-invocation-clone.", "" );
-                            temp.delete();
-                            temp.mkdirs();
-
-                            copyDirectoryStructure( projectsDirectory, temp );
-
-                            FileUtils.deleteDirectory( new File( temp, cloneSubdir ) );
-
-                            copyDirectoryStructure( temp, cloneProjectsTo );
-                        }
-                        else
-                        {
-                            copyDirectoryStructure( projectsDirectory, cloneProjectsTo );
-                        }
-                    }
-                    else
-                    {
-                        File srcDir = new File( projectsDirectory, subpath );
-                        File dstDir = new File( cloneProjectsTo, subpath );
-                        copyDirectoryStructure( srcDir, dstDir );
-                    }
-
-                    clonedSubpaths.add( subpath );
-                }
-            }
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( "Failed to clone projects from: " + projectsDirectory + " to: "
-                + cloneProjectsTo + ". Reason: " + e.getMessage(), e );
-        }
-
-        // filter cloned POMs
-        if ( filter )
-        {
-            for ( String projectPath : projectPaths )
-            {
-                File pomFile = new File( cloneProjectsTo, projectPath );
-                if ( pomFile.isFile() )
-                {
-                    buildInterpolatedFile( pomFile, pomFile );
-                }
-
-                // MINVOKER-186
-                // The following is a temporary solution to support Maven 3.3.1 (.mvn/extensions.xml) filtering
-                // Will be replaced by MINVOKER-117 with general filtering mechanism
-                File baseDir = pomFile.getParentFile();
-                File mvnDir = new File( baseDir, ".mvn" );
-                if ( mvnDir.isDirectory() )
-                {
-                    File extensionsFile = new File( mvnDir, "extensions.xml" );
-                    if ( extensionsFile.isFile() )
-                    {
-                        buildInterpolatedFile( extensionsFile, extensionsFile );
-                    }
-                }
-                // END MINVOKER-186
-            }
-            filteredPomPrefix = null;
-        }
-    }
-
-    /**
-     * Gets the parent path of the specified relative path.
-     *
-     * @param path The relative path whose parent should be retrieved, must not be <code>null</code>.
-     * @return The parent path or "." if the specified path has no parent, never <code>null</code>.
-     */
-    private String getParentPath( String path )
-    {
-        int lastSep = Math.max( path.lastIndexOf( '/' ), path.lastIndexOf( '\\' ) );
-        return ( lastSep < 0 ) ? "." : path.substring( 0, lastSep );
-    }
-
-    /**
-     * Copied a directory structure with default exclusions (.svn, CVS, etc)
-     *
-     * @param sourceDir The source directory to copy, must not be <code>null</code>.
-     * @param destDir The target directory to copy to, must not be <code>null</code>.
-     * @throws java.io.IOException If the directory structure could not be copied.
-     */
-    private void copyDirectoryStructure( File sourceDir, File destDir )
-        throws IOException
-    {
-        DirectoryScanner scanner = new DirectoryScanner();
-        scanner.setBasedir( sourceDir );
-        if ( !cloneAllFiles )
-        {
-            scanner.addDefaultExcludes();
-        }
-        scanner.scan();
-
-        /*
-         * NOTE: Make sure the destination directory is always there (even if empty) to support POM-less ITs.
-         */
-        destDir.mkdirs();
-        // Create all the directories, including any symlinks present in source
-        FileUtils.mkDirs( sourceDir, scanner.getIncludedDirectories(), destDir );
-
-        for ( String includedFile : scanner.getIncludedFiles() )
-        {
-            File sourceFile = new File( sourceDir, includedFile );
-            File destFile = new File( destDir, includedFile );
-            FileUtils.copyFile( sourceFile, destFile );
-
-            // ensure clone project must be writable for additional changes
-            destFile.setWritable( true );
-        }
-    }
-
-    /**
-     * Determines whether the specified sub path has already been cloned, i.e. whether one of its ancestor directories
-     * was already cloned.
-     *
-     * @param subpath The sub path to check, must not be <code>null</code>.
-     * @param clonedSubpaths The list of already cloned paths, must not be <code>null</code> nor contain
-     *            <code>null</code> elements.
-     * @return <code>true</code> if the specified path has already been cloned, <code>false</code> otherwise.
-     */
-    static boolean alreadyCloned( String subpath, List<String> clonedSubpaths )
-    {
-        for ( String path : clonedSubpaths )
-        {
-            if ( ".".equals( path ) || subpath.equals( path ) || subpath.startsWith( path + File.separator ) )
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Runs the specified build jobs.
-     *
-     * @param projectsDir The base directory of all projects, must not be <code>null</code>.
-     * @param buildJobs The build jobs to run must not be <code>null</code> nor contain <code>null</code> elements.
-     * @throws org.apache.maven.plugin.MojoExecutionException If any build could not be launched.
-     */
-    private void runBuilds( final File projectsDir, BuildJob[] buildJobs, int runWithParallelThreads )
-        throws MojoExecutionException
-    {
-        if ( !localRepositoryPath.exists() )
-        {
-            localRepositoryPath.mkdirs();
-        }
-
-        // -----------------------------------------------
-        // interpolate settings file
-        // -----------------------------------------------
-
-        File interpolatedSettingsFile = interpolateSettings();
-
-        final File mergedSettingsFile = mergeSettings( interpolatedSettingsFile );
-
-        if ( mavenHome != null )
-        {
-            actualMavenVersion = SelectorUtils.getMavenVersion( mavenHome );
-        }
-        else
-        {
-            actualMavenVersion = SelectorUtils.getMavenVersion();
-        }
-        scriptRunner.setGlobalVariable( "mavenVersion", actualMavenVersion );
-
-        final CharSequence actualJreVersion;
-        // @todo if ( javaVersions ) ... to be picked up from toolchains
-        if ( javaHome != null )
-        {
-            actualJreVersion = resolveExternalJreVersion();
-        }
-        else
-        {
-            actualJreVersion = SelectorUtils.getJreVersion();
-        }
-
-        try
-        {
-            if ( runWithParallelThreads > 1 )
-            {
-                getLog().info( "use parallelThreads " + runWithParallelThreads );
-
-                ExecutorService executorService = Executors.newFixedThreadPool( runWithParallelThreads );
-                for ( final BuildJob job : buildJobs )
-                {
-                    executorService.execute( new Runnable()
-                    {
-                        public void run()
-                        {
-                            try
-                            {
-                                runBuild( projectsDir, job, mergedSettingsFile, javaHome, actualJreVersion );
-                            }
-                            catch ( MojoExecutionException e )
-                            {
-                                throw new RuntimeException( e.getMessage(), e );
-                            }
-                        }
-                    } );
-                }
-
-                try
-                {
-                    executorService.shutdown();
-                    // TODO add a configurable time out
-                    executorService.awaitTermination( Long.MAX_VALUE, TimeUnit.MILLISECONDS );
-                }
-                catch ( InterruptedException e )
-                {
-                    throw new MojoExecutionException( e.getMessage(), e );
-                }
-            }
-            else
-            {
-                for ( BuildJob job : buildJobs )
-                {
-                    runBuild( projectsDir, job, mergedSettingsFile, javaHome, actualJreVersion );
-                }
-            }
-        }
-        finally
-        {
-            if ( interpolatedSettingsFile != null && cloneProjectsTo == null )
-            {
-                interpolatedSettingsFile.delete();
-            }
-            if ( mergedSettingsFile != null && mergedSettingsFile.exists() )
-            {
-                mergedSettingsFile.delete();
-            }
-        }
-    }
-
-    /**
-     * Interpolate settings.xml file.
-     * 
-     * @return The interpolated settings.xml file.
-     * @throws MojoExecutionException in case of a problem.
-     */
-    private File interpolateSettings()
-        throws MojoExecutionException
-    {
-        File interpolatedSettingsFile = null;
-        if ( settingsFile != null )
-        {
-            if ( cloneProjectsTo != null )
-            {
-                interpolatedSettingsFile = new File( cloneProjectsTo, "interpolated-" + settingsFile.getName() );
-            }
-            else
-            {
-                interpolatedSettingsFile =
-                    new File( settingsFile.getParentFile(), "interpolated-" + settingsFile.getName() );
-            }
-            buildInterpolatedFile( settingsFile, interpolatedSettingsFile );
-        }
-        return interpolatedSettingsFile;
-    }
-
-    /**
-     * Merge the settings file
-     * 
-     * @param interpolatedSettingsFile The interpolated settings file.
-     * @return The merged settings file.
-     * @throws MojoExecutionException Fail the build in case the merged settings file can't be created.
-     */
-    private File mergeSettings( File interpolatedSettingsFile )
-        throws MojoExecutionException
-    {
-        File mergedSettingsFile;
-        Settings mergedSettings = this.settings;
-        if ( mergeUserSettings )
-        {
-            if ( interpolatedSettingsFile != null )
-            {
-                // Have to merge the specified settings file (dominant) and the one of the invoking Maven process
-                try
-                {
-                    SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
-                    request.setGlobalSettingsFile( interpolatedSettingsFile );
-
-                    Settings dominantSettings = settingsBuilder.build( request ).getEffectiveSettings();
-                    Settings recessiveSettings = cloneSettings();
-                    SettingsUtils.merge( dominantSettings, recessiveSettings, TrackableBase.USER_LEVEL );
-
-                    mergedSettings = dominantSettings;
-                    getLog().debug( "Merged specified settings file with settings of invoking process" );
-                }
-                catch ( SettingsBuildingException e )
-                {
-                    throw new MojoExecutionException( "Could not read specified settings file", e );
-                }
-            }
-        }
-
-        if ( this.settingsFile != null && !mergeUserSettings )
-        {
-            mergedSettingsFile = interpolatedSettingsFile;
-        }
-        else
-        {
-            try
-            {
-                mergedSettingsFile = writeMergedSettingsFile( mergedSettings );
-            }
-            catch ( IOException e )
-            {
-                throw new MojoExecutionException( "Could not create temporary file for invoker settings.xml", e );
-            }
-        }
-        return mergedSettingsFile;
-    }
-
-    private File writeMergedSettingsFile( Settings mergedSettings )
-        throws IOException
-    {
-        File mergedSettingsFile;
-        mergedSettingsFile = File.createTempFile( "invoker-settings", ".xml" );
-
-        SettingsXpp3Writer settingsWriter = new SettingsXpp3Writer();
-
-        FileWriter fileWriter = null;
-        try
-        {
-            fileWriter = new FileWriter( mergedSettingsFile );
-            settingsWriter.write( fileWriter, mergedSettings );
-            fileWriter.close();
-            fileWriter = null;
-        }
-        finally
-        {
-            IOUtil.close( fileWriter );
-        }
-
-        if ( getLog().isDebugEnabled() )
-        {
-            getLog().debug( "Created temporary file for invoker settings.xml: "
-                + mergedSettingsFile.getAbsolutePath() );
-        }
-        return mergedSettingsFile;
-    }
-
-    private Settings cloneSettings()
-    {
-        Settings recessiveSettings = SettingsUtils.copySettings( this.settings );
-
-        // MINVOKER-133: reset sourceLevelSet
-        resetSourceLevelSet( recessiveSettings );
-        for ( org.apache.maven.settings.Mirror mirror : recessiveSettings.getMirrors() )
-        {
-            resetSourceLevelSet( mirror );
-        }
-        for ( org.apache.maven.settings.Server server : recessiveSettings.getServers() )
-        {
-            resetSourceLevelSet( server );
-        }
-        for ( org.apache.maven.settings.Proxy proxy : recessiveSettings.getProxies() )
-        {
-            resetSourceLevelSet( proxy );
-        }
-        for ( org.apache.maven.settings.Profile profile : recessiveSettings.getProfiles() )
-        {
-            resetSourceLevelSet( profile );
-        }
-
-        return recessiveSettings;
-    }
-
-    private void resetSourceLevelSet( org.apache.maven.settings.TrackableBase trackable )
-    {
-        try
-        {
-            ReflectionUtils.setVariableValueInObject( trackable, "sourceLevelSet", Boolean.FALSE );
-            getLog().debug( "sourceLevelSet: "
-                + ReflectionUtils.getValueIncludingSuperclasses( "sourceLevelSet", trackable ) );
-        }
-        catch ( IllegalAccessException e )
-        {
-            // noop
-        }
-    }
-
-    private CharSequence resolveExternalJreVersion()
-    {
-        Artifact pluginArtifact = mojoExecution.getMojoDescriptor().getPluginDescriptor().getPluginArtifact();
-        pluginArtifact.getFile();
-
-        Commandline commandLine = new Commandline();
-        commandLine.setExecutable( new File( javaHome, "bin/java" ).getAbsolutePath() );
-        commandLine.createArg().setValue( "-cp" );
-        commandLine.createArg().setFile( pluginArtifact.getFile() );
-        commandLine.createArg().setValue( SystemPropertyPrinter.class.getName() );
-        commandLine.createArg().setValue( "java.version" );
-
-        final StringBuilder actualJreVersion = new StringBuilder();
-        StreamConsumer consumer = new StreamConsumer()
-        {
-            public void consumeLine( String line )
-            {
-                actualJreVersion.append( line );
-            }
-        };
-        try
-        {
-            CommandLineUtils.executeCommandLine( commandLine, consumer, null );
-        }
-        catch ( CommandLineException e )
-        {
-            getLog().warn( e.getMessage() );
-        }
-        return actualJreVersion;
-    }
-
-    /**
-     * Interpolate the pom file.
-     * 
-     * @param pomFile The pom file.
-     * @param basedir The base directory.
-     * @return interpolated pom file location in case we have interpolated the pom file otherwise the original pom file
-     *         will be returned.
-     * @throws MojoExecutionException
-     */
-    private File interpolatePomFile( File pomFile, File basedir )
-        throws MojoExecutionException
-    {
-        File interpolatedPomFile = null;
-        if ( pomFile != null )
-        {
-            if ( StringUtils.isNotEmpty( filteredPomPrefix ) )
-            {
-                interpolatedPomFile = new File( basedir, filteredPomPrefix + pomFile.getName() );
-                buildInterpolatedFile( pomFile, interpolatedPomFile );
-            }
-            else
-            {
-                interpolatedPomFile = pomFile;
-            }
-        }
-        return interpolatedPomFile;
-    }
-
-    /**
-     * Runs the specified project.
-     *
-     * @param projectsDir The base directory of all projects, must not be <code>null</code>.
-     * @param buildJob The build job to run, must not be <code>null</code>.
-     * @param settingsFile The (already interpolated) user settings file for the build, may be <code>null</code> to use
-     *            the current user settings.
-     * @throws org.apache.maven.plugin.MojoExecutionException If the project could not be launched.
-     */
-    private void runBuild( File projectsDir, BuildJob buildJob, File settingsFile, File actualJavaHome,
-                           CharSequence actualJreVersion )
-        throws MojoExecutionException
-    {
-        // FIXME: Think about the following code part -- START
-        File pomFile = new File( projectsDir, buildJob.getProject() );
-        File basedir;
-        if ( pomFile.isDirectory() )
-        {
-            basedir = pomFile;
-            pomFile = new File( basedir, "pom.xml" );
-            if ( !pomFile.exists() )
-            {
-                pomFile = null;
-            }
-            else
-            {
-                buildJob.setProject( buildJob.getProject() + File.separator + "pom.xml" );
-            }
-        }
-        else
-        {
-            basedir = pomFile.getParentFile();
-        }
-
-        File interpolatedPomFile = interpolatePomFile( pomFile, basedir );
-        // FIXME: Think about the following code part -- ^^^^^^^ END
-
-        getLog().info( buffer().a( "Building: " ).strong( buildJob.getProject() ).toString() );
-
-        InvokerProperties invokerProperties = getInvokerProperties( basedir );
-
-        // let's set what details we can
-        buildJob.setName( invokerProperties.getJobName() );
-        buildJob.setDescription( invokerProperties.getJobDescription() );
-
-        try
-        {
-            int selection = getSelection( invokerProperties, actualJreVersion );
-            if ( selection == 0 )
-            {
-                long milliseconds = System.currentTimeMillis();
-                boolean executed;
-                try
-                {
-                    // CHECKSTYLE_OFF: LineLength
-                    executed =
-                        runBuild( basedir, interpolatedPomFile, settingsFile, actualJavaHome, invokerProperties );
-                    // CHECKSTYLE_ON: LineLength
-                }
-                finally
-                {
-                    milliseconds = System.currentTimeMillis() - milliseconds;
-                    buildJob.setTime( milliseconds / 1000.0 );
-                }
-
-                if ( executed )
-                {
-                    buildJob.setResult( BuildJob.Result.SUCCESS );
-
-                    if ( !suppressSummaries )
-                    {
-                        getLog().info( pad( buildJob ).success( "SUCCESS" ).a( ' ' )
-                            + formatTime( buildJob.getTime() ) );
-                    }
-                }
-                else
-                {
-                    buildJob.setResult( BuildJob.Result.SKIPPED );
-
-                    if ( !suppressSummaries )
-                    {
-                        getLog().info( pad( buildJob ).warning( "SKIPPED" ).a( ' ' )
-                            + formatTime( buildJob.getTime() ) );
-                    }
-                }
-            }
-            else
-            {
-                buildJob.setResult( BuildJob.Result.SKIPPED );
-
-                StringBuilder message = new StringBuilder();
-                if ( selection == Selector.SELECTOR_MULTI )
-                {
-                    message.append( "non-matching selectors" );
-                }
-                else
-                {
-                    if ( ( selection & Selector.SELECTOR_MAVENVERSION ) != 0 )
-                    {
-                        message.append( "Maven version" );
-                    }
-                    if ( ( selection & Selector.SELECTOR_JREVERSION ) != 0 )
-                    {
-                        if ( message.length() > 0 )
-                        {
-                            message.append( ", " );
-                        }
-                        message.append( "JRE version" );
-                    }
-                    if ( ( selection & Selector.SELECTOR_OSFAMILY ) != 0 )
-                    {
-                        if ( message.length() > 0 )
-                        {
-                            message.append( ", " );
-                        }
-                        message.append( "OS" );
-                    }
-                }
-
-                if ( !suppressSummaries )
-                {
-                    getLog().info( pad( buildJob ).warning( "SKIPPED" ) + " due to " + message.toString() );
-                }
-
-                // Abuse failureMessage, the field in the report which should contain the reason for skipping
-                // Consider skipCode + I18N
-                buildJob.setFailureMessage( "Skipped due to " + message.toString() );
-            }
-        }
-        catch ( RunErrorException e )
-        {
-            buildJob.setResult( BuildJob.Result.ERROR );
-            buildJob.setFailureMessage( e.getMessage() );
-
-            if ( !suppressSummaries )
-            {
-                getLog().info( pad( buildJob ).failure( "ERROR" ).a( ' ' ) + formatTime( buildJob.getTime() ) );
-                getLog().info( "  " + e.getMessage() );
-            }
-        }
-        catch ( RunFailureException e )
-        {
-            buildJob.setResult( e.getType() );
-            buildJob.setFailureMessage( e.getMessage() );
-
-            if ( !suppressSummaries )
-            {
-                getLog().info( pad( buildJob ).failure( "FAILED" ).a( ' ' ) + formatTime( buildJob.getTime() ) );
-                getLog().info( "  " + e.getMessage() );
-            }
-        }
-        finally
-        {
-            deleteInterpolatedPomFile( interpolatedPomFile );
-            writeBuildReport( buildJob );
-        }
-    }
-
-    private MessageBuilder pad( BuildJob buildJob )
-    {
-        MessageBuilder buffer = buffer( 128 );
-
-        buffer.a( "          " );
-        buffer.a( buildJob.getProject() );
-        buffer.a( ' ' );
-
-        int l = 11 + buildJob.getProject().length();
-
-        if ( l < RESULT_COLUMN )
-        {
-            for ( int i = RESULT_COLUMN - l; i > 0; i-- )
-            {
-                buffer.a( '.' );
-            }
-        }
-
-        return buffer.a( ' ' );
-    }
-
-    /**
-     * Delete the interpolated pom file if it has been created before.
-     * 
-     * @param interpolatedPomFile The interpolated pom file.
-     */
-    private void deleteInterpolatedPomFile( File interpolatedPomFile )
-    {
-        if ( interpolatedPomFile != null && StringUtils.isNotEmpty( filteredPomPrefix ) )
-        {
-            interpolatedPomFile.delete();
-        }
-    }
-
-    /**
-     * Determines whether selector conditions of the specified invoker properties match the current environment.
-     *
-     * @param invokerProperties The invoker properties to check, must not be <code>null</code>.
-     * @return <code>0</code> if the job corresponding to the properties should be run, otherwise a bitwise value
-     *         representing the reason why it should be skipped.
-     */
-    private int getSelection( InvokerProperties invokerProperties, CharSequence actualJreVersion )
-    {
-        return new Selector( actualMavenVersion, actualJreVersion.toString() ).getSelection( invokerProperties );
-    }
-
-    /**
-     * Writes the XML report for the specified build job unless report generation has been disabled.
-     *
-     * @param buildJob The build job whose report should be written, must not be <code>null</code>.
-     * @throws org.apache.maven.plugin.MojoExecutionException If the report could not be written.
-     */
-    private void writeBuildReport( BuildJob buildJob )
-        throws MojoExecutionException
-    {
-        if ( disableReports )
-        {
-            return;
-        }
-
-        String safeFileName = buildJob.getProject().replace( '/', '_' ).replace( '\\', '_' ).replace( ' ', '_' );
-        if ( safeFileName.endsWith( "_pom.xml" ) )
-        {
-            safeFileName = safeFileName.substring( 0, safeFileName.length() - "_pom.xml".length() );
-        }
-
-        File reportFile = new File( reportsDirectory, "BUILD-" + safeFileName + ".xml" );
-        try
-        {
-            FileOutputStream fos = new FileOutputStream( reportFile );
-            try
-            {
-                Writer osw = new OutputStreamWriter( fos, buildJob.getModelEncoding() );
-                BuildJobXpp3Writer writer = new BuildJobXpp3Writer();
-                writer.write( osw, buildJob );
-                osw.close();
-            }
-            finally
-            {
-                fos.close();
-            }
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( "Failed to write build report " + reportFile, e );
-        }
-    }
-
-    /**
-     * Formats the specified build duration time.
-     *
-     * @param seconds The duration of the build.
-     * @return The formatted time, never <code>null</code>.
-     */
-    private String formatTime( double seconds )
-    {
-        return secFormat.format( seconds );
-    }
-
-    /**
-     * Runs the specified project.
-     *
-     * @param basedir The base directory of the project, must not be <code>null</code>.
-     * @param pomFile The (already interpolated) POM file, may be <code>null</code> for a POM-less Maven invocation.
-     * @param settingsFile The (already interpolated) user settings file for the build, may be <code>null</code>. Will
-     *            be merged with the settings file of the invoking Maven process.
-     * @param invokerProperties The properties to use.
-     * @return <code>true</code> if the project was launched or <code>false</code> if the selector script indicated that
-     *         the project should be skipped.
-     * @throws org.apache.maven.plugin.MojoExecutionException If the project could not be launched.
-     * @throws org.apache.maven.shared.scriptinterpreter.RunFailureException If either a hook script or the build itself
-     *             failed.
-     */
-    private boolean runBuild( File basedir, File pomFile, File settingsFile, File actualJavaHome,
-                              InvokerProperties invokerProperties )
-        throws MojoExecutionException, RunFailureException
-    {
-        if ( getLog().isDebugEnabled() && !invokerProperties.getProperties().isEmpty() )
-        {
-            Properties props = invokerProperties.getProperties();
-            getLog().debug( "Using invoker properties:" );
-            for ( String key : new TreeSet<String>( props.stringPropertyNames() ) )
-            {
-                String value = props.getProperty( key );
-                getLog().debug( "  " + key + " = " + value );
-            }
-        }
-
-        List<String> goals = getGoals( basedir );
-
-        List<String> profiles = getProfiles( basedir );
-
-        Map<String, Object> context = new LinkedHashMap<String, Object>();
-
-        FileLogger logger = setupBuildLogFile( basedir );
-        try
-        {
-            try
-            {
-                scriptRunner.run( "selector script", basedir, selectorScript, context, logger, BuildJob.Result.SKIPPED,
-                                  false );
-            }
-            catch ( RunErrorException e )
-            {
-                throw e;
-            }
-            catch ( RunFailureException e )
-            {
-                return false;
-            }
-
-            scriptRunner.run( "pre-build script", basedir, preBuildHookScript, context, logger,
-                              BuildJob.Result.FAILURE_PRE_HOOK, false );
-
-            final InvocationRequest request = new DefaultInvocationRequest();
-
-            request.setLocalRepositoryDirectory( localRepositoryPath );
-
-            request.setBatchMode( true );
-
-            request.setShowErrors( showErrors );
-
-            request.setDebug( debug );
-
-            request.setShowVersion( showVersion );
-
-            setupLoggerForBuildJob( logger, request );
-
-            if ( mavenHome != null )
-            {
-                invoker.setMavenHome( mavenHome );
-                // FIXME: Should we really take care of M2_HOME?
-                request.addShellEnvironment( "M2_HOME", mavenHome.getAbsolutePath() );
-            }
-
-            if ( mavenExecutable != null )
-            {
-                invoker.setMavenExecutable( new File( mavenExecutable ) );
-            }
-
-            if ( actualJavaHome != null )
-            {
-                request.setJavaHome( actualJavaHome );
-            }
-
-            if ( environmentVariables != null )
-            {
-                for ( Map.Entry<String, String> variable : environmentVariables.entrySet() )
-                {
-                    request.addShellEnvironment( variable.getKey(), variable.getValue() );
-                }
-            }
-
-            for ( int invocationIndex = 1;; invocationIndex++ )
-            {
-                if ( invocationIndex > 1 && !invokerProperties.isInvocationDefined( invocationIndex ) )
-                {
-                    break;
-                }
-
-                request.setBaseDirectory( basedir );
-
-                request.setPomFile( pomFile );
-
-                request.setGoals( goals );
-
-                request.setProfiles( profiles );
-
-                request.setMavenOpts( mavenOpts );
-
-                request.setOffline( false );
-
-                request.setUserSettingsFile( settingsFile );
-
-                Properties systemProperties =
-                    getSystemProperties( basedir, invokerProperties.getSystemPropertiesFile( invocationIndex ) );
-                request.setProperties( systemProperties );
-
-                invokerProperties.configureInvocation( request, invocationIndex );
-
-                if ( getLog().isDebugEnabled() )
-                {
-                    try
-                    {
-                        getLog().debug( "Using MAVEN_OPTS: " + request.getMavenOpts() );
-                        getLog().debug( "Executing: " + new MavenCommandLineBuilder().build( request ) );
-                    }
-                    catch ( CommandLineConfigurationException e )
-                    {
-                        getLog().debug( "Failed to display command line: " + e.getMessage() );
-                    }
-                }
-
-                InvocationResult result;
-
-                try
-                {
-                    result = invoker.execute( request );
-                }
-                catch ( final MavenInvocationException e )
-                {
-                    getLog().debug( "Error invoking Maven: " + e.getMessage(), e );
-                    throw new RunFailureException( "Maven invocation failed. " + e.getMessage(),
-                                                   BuildJob.Result.FAILURE_BUILD );
-                }
-
-                verify( result, invocationIndex, invokerProperties, logger );
-            }
-
-            scriptRunner.run( "post-build script", basedir, postBuildHookScript, context, logger,
-                              BuildJob.Result.FAILURE_POST_HOOK, true );
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( e.getMessage(), e );
-        }
-        finally
-        {
-            if ( logger != null )
-            {
-                logger.close();
-            }
-        }
-        return true;
-    }
-
-    private void setupLoggerForBuildJob( FileLogger logger, final InvocationRequest request )
-    {
-        if ( logger != null )
-        {
-            request.setErrorHandler( logger );
-
-            request.setOutputHandler( logger );
-        }
-    }
-
-    /**
-     * Initializes the build logger for the specified project. This will write the logging information into
-     * {@code build.log}.
-     *
-     * @param basedir The base directory of the project, must not be <code>null</code>.
-     * @return The build logger or <code>null</code> if logging has been disabled.
-     * @throws org.apache.maven.plugin.MojoExecutionException If the log file could not be created.
-     */
-    private FileLogger setupBuildLogFile( File basedir )
-        throws MojoExecutionException
-    {
-        FileLogger logger = null;
-
-        if ( !noLog )
-        {
-            File outputLog = new File( basedir, "build.log" );
-            try
-            {
-                if ( streamLogs )
-                {
-                    logger = new FileLogger( outputLog, getLog() );
-                }
-                else
-                {
-                    logger = new FileLogger( outputLog );
-                }
-
-                getLog().debug( "Build log initialized in: " + outputLog );
-            }
-            catch ( IOException e )
-            {
-                throw new MojoExecutionException( "Error initializing build logfile in: " + outputLog, e );
-            }
-        }
-
-        return logger;
-    }
-
-    /**
-     * Gets the system properties to use for the specified project.
-     *
-     * @param basedir The base directory of the project, must not be <code>null</code>.
-     * @param filename The filename to the properties file to load, may be <code>null</code> to use the default path
-     *            given by {@link #testPropertiesFile}.
-     * @return The system properties to use, may be empty but never <code>null</code>.
-     * @throws org.apache.maven.plugin.MojoExecutionException If the properties file exists but could not be read.
-     */
-    private Properties getSystemProperties( final File basedir, final String filename )
-        throws MojoExecutionException
-    {
-        Properties collectedTestProperties = new Properties();
-
-        if ( properties != null )
-        {
-            // MINVOKER-118: property can have empty value, which is not accepted by collectedTestProperties
-            for ( Map.Entry<String, String> entry : properties.entrySet() )
-            {
-                if ( entry.getValue() != null )
-                {
-                    collectedTestProperties.put( entry.getKey(), entry.getValue() );
-                }
-            }
-        }
-
-        File propertiesFile = null;
-        if ( filename != null )
-        {
-            propertiesFile = new File( basedir, filename );
-        }
-        else if ( testPropertiesFile != null )
-        {
-            propertiesFile = new File( basedir, testPropertiesFile );
-        }
-
-        if ( propertiesFile != null && propertiesFile.isFile() )
-        {
-            InputStream fin = null;
-            try
-            {
-                fin = new FileInputStream( propertiesFile );
-
-                Properties loadedProperties = new Properties();
-                loadedProperties.load( fin );
-                fin.close();
-                fin = null;
-                collectedTestProperties.putAll( loadedProperties );
-            }
-            catch ( IOException e )
-            {
-                throw new MojoExecutionException( "Error reading system properties from " + propertiesFile );
-            }
-            finally
-            {
-                IOUtil.close( fin );
-            }
-        }
-
-        return collectedTestProperties;
-    }
-
-    /**
-     * Verifies the invocation result.
-     *
-     * @param result The invocation result to check, must not be <code>null</code>.
-     * @param invocationIndex The index of the invocation for which to check the exit code, must not be negative.
-     * @param invokerProperties The invoker properties used to check the exit code, must not be <code>null</code>.
-     * @param logger The build logger, may be <code>null</code> if logging is disabled.
-     * @throws org.apache.maven.shared.scriptinterpreter.RunFailureException If the invocation result indicates a build
-     *             failure.
-     */
-    private void verify( InvocationResult result, int invocationIndex, InvokerProperties invokerProperties,
-                         FileLogger logger )
-        throws RunFailureException
-    {
-        if ( result.getExecutionException() != null )
-        {
-            throw new RunFailureException( "The Maven invocation failed. "
-                + result.getExecutionException().getMessage(), BuildJob.Result.ERROR );
-        }
-        else if ( !invokerProperties.isExpectedResult( result.getExitCode(), invocationIndex ) )
-        {
-            StringBuilder buffer = new StringBuilder( 256 );
-            buffer.append( "The build exited with code " ).append( result.getExitCode() ).append( ". " );
-            if ( logger != null )
-            {
-                buffer.append( "See " );
-                buffer.append( logger.getOutputFile().getAbsolutePath() );
-                buffer.append( " for details." );
-            }
-            else
-            {
-                buffer.append( "See console output for details." );
-            }
-            throw new RunFailureException( buffer.toString(), BuildJob.Result.FAILURE_BUILD );
-        }
-    }
-
-    /**
-     * Gets the goal list for the specified project.
-     *
-     * @param basedir The base directory of the project, must not be <code>null</code>.
-     * @return The list of goals to run when building the project, may be empty but never <code>null</code>.
-     * @throws org.apache.maven.plugin.MojoExecutionException If the profile file could not be read.
-     */
-    List<String> getGoals( final File basedir )
-        throws MojoExecutionException
-    {
-        try
-        {
-            // FIXME: Currently we have null for goalsFile which has been removed.
-            // This might mean we can remove getGoals() at all ? Check this.
-            return getTokens( basedir, null, goals );
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( "error reading goals", e );
-        }
-    }
-
-    /**
-     * Gets the profile list for the specified project.
-     *
-     * @param basedir The base directory of the project, must not be <code>null</code>.
-     * @return The list of profiles to activate when building the project, may be empty but never <code>null</code>.
-     * @throws org.apache.maven.plugin.MojoExecutionException If the profile file could not be read.
-     */
-    List<String> getProfiles( File basedir )
-        throws MojoExecutionException
-    {
-        try
-        {
-            return getTokens( basedir, null, profiles );
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( "error reading profiles", e );
-        }
-    }
-
-    private List<String> calculateExcludes()
-        throws IOException
-    {
-        List<String> excludes =
-            ( pomExcludes != null ) ? new ArrayList<String>( pomExcludes ) : new ArrayList<String>();
-        if ( this.settingsFile != null )
-        {
-            String exclude = relativizePath( this.settingsFile, projectsDirectory.getCanonicalPath() );
-            if ( exclude != null )
-            {
-                excludes.add( exclude.replace( '\\', '/' ) );
-                getLog().debug( "Automatically excluded " + exclude + " from project scanning" );
-            }
-        }
-        return excludes;
-
-    }
-
-    /**
-     * @return The list of setupUp jobs.
-     * @throws IOException
-     * @see {@link #setupIncludes}
-     */
-    private BuildJob[] getSetupBuildJobsFromFolders()
-        throws IOException
-    {
-        List<String> excludes = calculateExcludes();
-
-        BuildJob[] setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP );
-        if ( getLog().isDebugEnabled() )
-        {
-            getLog().debug( "Setup projects: " + Arrays.asList( setupPoms ) );
-        }
-
-        return setupPoms;
-    }
-
-    /**
-     * Gets the build jobs that should be processed. Note that the order of the returned build jobs is significant.
-     *
-     * @return The build jobs to process, may be empty but never <code>null</code>.
-     * @throws java.io.IOException If the projects directory could not be scanned.
-     */
-    BuildJob[] getBuildJobs()
-        throws IOException
-    {
-        BuildJob[] buildJobs;
-
-        if ( invokerTest == null )
-        {
-            List<String> excludes = calculateExcludes();
-
-            BuildJob[] setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP );
-            if ( getLog().isDebugEnabled() )
-            {
-                getLog().debug( "Setup projects: " + Arrays.asList( setupPoms ) );
-            }
-
-            BuildJob[] normalPoms = scanProjectsDirectory( pomIncludes, excludes, BuildJob.Type.NORMAL );
-
-            Map<String, BuildJob> uniquePoms = new LinkedHashMap<String, BuildJob>();
-            for ( BuildJob setupPom : setupPoms )
-            {
-                uniquePoms.put( setupPom.getProject(), setupPom );
-            }
-            for ( BuildJob normalPom : normalPoms )
-            {
-                if ( !uniquePoms.containsKey( normalPom.getProject() ) )
-                {
-                    uniquePoms.put( normalPom.getProject(), normalPom );
-                }
-            }
-
-            buildJobs = uniquePoms.values().toArray( new BuildJob[uniquePoms.size()] );
-        }
-        else
-        {
-            String[] testRegexes = StringUtils.split( invokerTest, "," );
-            List<String> includes = new ArrayList<String>( testRegexes.length );
-            List<String> excludes = new ArrayList<String>();
-
-            for ( String regex : testRegexes )
-            {
-                // user just use -Dinvoker.test=MWAR191,MNG111 to use a directory thats the end is not pom.xml
-                if ( regex.startsWith( "!" ) )
-                {
-                    excludes.add( regex.substring( 1 ) );
-                }
-                else
-                {
-                    includes.add( regex );
-                }
-            }
-
-            // it would be nice if we could figure out what types these are... but perhaps
-            // not necessary for the -Dinvoker.test=xxx t
-            buildJobs = scanProjectsDirectory( includes, excludes, BuildJob.Type.DIRECT );
-        }
-
-        relativizeProjectPaths( buildJobs );
-
-        return buildJobs;
-    }
-
-    /**
-     * Scans the projects directory for projects to build. Both (POM) files and mere directories will be matched by the
-     * scanner patterns. If the patterns match a directory which contains a file named "pom.xml", the results will
-     * include the path to this file rather than the directory path in order to avoid duplicate invocations of the same
-     * project.
-     *
-     * @param includes The include patterns for the scanner, may be <code>null</code>.
-     * @param excludes The exclude patterns for the scanner, may be <code>null</code> to exclude nothing.
-     * @param type The type to assign to the resulting build jobs, must not be <code>null</code>.
-     * @return The build jobs matching the patterns, never <code>null</code>.
-     * @throws java.io.IOException If the project directory could not be scanned.
-     */
-    private BuildJob[] scanProjectsDirectory( List<String> includes, List<String> excludes, String type )
-        throws IOException
-    {
-        if ( !projectsDirectory.isDirectory() )
-        {
-            return new BuildJob[0];
-        }
-
-        DirectoryScanner scanner = new DirectoryScanner();
-        scanner.setBasedir( projectsDirectory.getCanonicalFile() );
-        scanner.setFollowSymlinks( false );
-        if ( includes != null )
-        {
-            scanner.setIncludes( includes.toArray( new String[includes.size()] ) );
-        }
-        if ( excludes != null )
-        {
-            scanner.setExcludes( excludes.toArray( new String[excludes.size()] ) );
-        }
-        scanner.addDefaultExcludes();
-        scanner.scan();
-
-        Map<String, BuildJob> matches = new LinkedHashMap<String, BuildJob>();
-
-        for ( String includedFile : scanner.getIncludedFiles() )
-        {
-            matches.put( includedFile, new BuildJob( includedFile, type ) );
-        }
-
-        for ( String includedDir : scanner.getIncludedDirectories() )
-        {
-            String includedFile = includedDir + File.separatorChar + "pom.xml";
-            if ( new File( scanner.getBasedir(), includedFile ).isFile() )
-            {
-                matches.put( includedFile, new BuildJob( includedFile, type ) );
-            }
-            else
-            {
-                matches.put( includedDir, new BuildJob( includedDir, type ) );
-            }
-        }
-
-        return matches.values().toArray( new BuildJob[matches.size()] );
-    }
-
-    /**
-     * Relativizes the project paths of the specified build jobs against the directory specified by
-     * {@link #projectsDirectory} (if possible). If a project path does not denote a sub path of the projects directory,
-     * it is returned as is.
-     *
-     * @param buildJobs The build jobs whose project paths should be relativized, must not be <code>null</code> nor
-     *            contain <code>null</code> elements.
-     * @throws java.io.IOException If any path could not be relativized.
-     */
-    private void relativizeProjectPaths( BuildJob[] buildJobs )
-        throws IOException
-    {
-        String projectsDirPath = projectsDirectory.getCanonicalPath();
-
-        for ( BuildJob buildJob : buildJobs )
-        {
-            String projectPath = buildJob.getProject();
-
-            File file = new File( projectPath );
-
-            if ( !file.isAbsolute() )
-            {
-                file = new File( projectsDirectory, projectPath );
-            }
-
-            String relativizedPath = relativizePath( file, projectsDirPath );
-
-            if ( relativizedPath == null )
-            {
-                relativizedPath = projectPath;
-            }
-
-            buildJob.setProject( relativizedPath );
-        }
-    }
-
-    /**
-     * Relativizes the specified path against the given base directory. Besides relativization, the returned path will
-     * also be normalized, e.g. directory references like ".." will be removed.
-     *
-     * @param path The path to relativize, must not be <code>null</code>.
-     * @param basedir The (canonical path of the) base directory to relativize against, must not be <code>null</code>.
-     * @return The relative path in normal form or <code>null</code> if the input path does not denote a sub path of the
-     *         base directory.
-     * @throws java.io.IOException If the path could not be relativized.
-     */
-    private String relativizePath( File path, String basedir )
-        throws IOException
-    {
-        String relativizedPath = path.getCanonicalPath();
-
-        if ( relativizedPath.startsWith( basedir ) )
-        {
-            relativizedPath = relativizedPath.substring( basedir.length() );
-            if ( relativizedPath.startsWith( File.separator ) )
-            {
-                relativizedPath = relativizedPath.substring( File.separator.length() );
-            }
-
-            return relativizedPath;
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    /**
-     * Returns the map-based value source used to interpolate POMs and other stuff.
-     *
-     * @param escapeXml {@code true}, to escape any XML special characters in the property values; {@code false}, to not
-     * escape any property values.
-     *
-     * @return The map-based value source for interpolation, never <code>null</code>.
-     */
-    private Map<String, Object> getInterpolationValueSource( final boolean escapeXml )
-    {
-        Map<String, Object> props = new HashMap<String, Object>();
-
-        if ( filterProperties != null )
-        {
-            props.putAll( filterProperties );
-        }
-        props.put( "basedir", this.project.getBasedir().getAbsolutePath() );
-        props.put( "baseurl", toUrl( this.project.getBasedir().getAbsolutePath() ) );
-        if ( settings.getLocalRepository() != null )
-        {
-            props.put( "localRepository", settings.getLocalRepository() );
-            props.put( "localRepositoryUrl", toUrl( settings.getLocalRepository() ) );
-        }
-
-        return new CompositeMap( this.project, props, escapeXml );
-    }
-
-    /**
-     * Converts the specified filesystem path to a URL. The resulting URL has no trailing slash regardless whether the
-     * path denotes a file or a directory.
-     *
-     * @param filename The filesystem path to convert, must not be <code>null</code>.
-     * @return The <code>file:</code> URL for the specified path, never <code>null</code>.
-     */
-    private static String toUrl( String filename )
-    {
-        /*
-         * NOTE: Maven fails to properly handle percent-encoded "file:" URLs (WAGON-111) so don't use File.toURI() here
-         * as-is but use the decoded path component in the URL.
-         */
-        String url = "file://" + new File( filename ).toURI().getPath();
-        if ( url.endsWith( "/" ) )
-        {
-            url = url.substring( 0, url.length() - 1 );
-        }
-        return url;
-    }
-
-    /**
-     * Gets goal/profile names for the specified project, either directly from the plugin configuration or from an
-     * external token file.
-     *
-     * @param basedir The base directory of the test project, must not be <code>null</code>.
-     * @param filename The (simple) name of an optional file in the project base directory from which to read
-     *            goals/profiles, may be <code>null</code>.
-     * @param defaultTokens The list of tokens to return in case the specified token file does not exist, may be
-     *            <code>null</code>.
-     * @return The list of goal/profile names, may be empty but never <code>null</code>.
-     * @throws java.io.IOException If the token file exists but could not be parsed.
-     */
-    private List<String> getTokens( File basedir, String filename, List<String> defaultTokens )
-        throws IOException
-    {
-        List<String> tokens = ( defaultTokens != null ) ? defaultTokens : new ArrayList<String>();
-
-        if ( StringUtils.isNotEmpty( filename ) )
-        {
-            File tokenFile = new File( basedir, filename );
-
-            if ( tokenFile.exists() )
-            {
-                tokens = readTokens( tokenFile );
-            }
-        }
-
-        return tokens;
-    }
-
-    /**
-     * Reads the tokens from the specified file. Tokens are separated either by line terminators or commas. During
-     * parsing, the file contents will be interpolated.
-     *
-     * @param tokenFile The file to read the tokens from, must not be <code>null</code>.
-     * @return The list of tokens, may be empty but never <code>null</code>.
-     * @throws java.io.IOException If the token file could not be read.
-     */
-    private List<String> readTokens( final File tokenFile )
-        throws IOException
-    {
-        List<String> result = new ArrayList<String>();
-
-        BufferedReader reader = null;
-        try
-        {
-            Map<String, Object> composite = getInterpolationValueSource( false );
-            reader = new BufferedReader( new InterpolationFilterReader( newReader( tokenFile ), composite ) );
-
-            for ( String line = reader.readLine(); line != null; line = reader.readLine() )
-            {
-                result.addAll( collectListFromCSV( line ) );
-            }
-
-            reader.close();
-            reader = null;
-        }
-        finally
-        {
-            IOUtil.close( reader );
-        }
-
-        return result;
-    }
-
-    /**
-     * Gets a list of comma separated tokens from the specified line.
-     *
-     * @param csv The line with comma separated tokens, may be <code>null</code>.
-     * @return The list of tokens from the line, may be empty but never <code>null</code>.
-     */
-    private List<String> collectListFromCSV( final String csv )
-    {
-        final List<String> result = new ArrayList<String>();
-
-        if ( ( csv != null ) && ( csv.trim().length() > 0 ) )
-        {
-            final StringTokenizer st = new StringTokenizer( csv, "," );
-
-            while ( st.hasMoreTokens() )
-            {
-                result.add( st.nextToken().trim() );
-            }
-        }
-
-        return result;
-    }
-
-    /**
-     * Interpolates the specified POM/settings file to a temporary file. The destination file may be same as the input
-     * file, i.e. interpolation can be performed in-place.
-     * <p>
-     * <b>Note:</b>This methods expects the file to be a XML file and applies special XML escaping during interpolation.
-     * </p>
-     *
-     * @param originalFile The XML file to interpolate, must not be <code>null</code>.
-     * @param interpolatedFile The target file to write the interpolated contents of the original file to, must not be
-     * <code>null</code>.
-     *
-     * @throws org.apache.maven.plugin.MojoExecutionException If the target file could not be created.
-     */
-    void buildInterpolatedFile( File originalFile, File interpolatedFile )
-        throws MojoExecutionException
-    {
-        getLog().debug( "Interpolate " + originalFile.getPath() + " to " + interpolatedFile.getPath() );
-
-        try
-        {
-            String xml;
-
-            Reader reader = null;
-            try
-            {
-                // interpolation with token @...@
-                Map<String, Object> composite = getInterpolationValueSource( true );
-                reader =
-                    new InterpolationFilterReader( ReaderFactory.newXmlReader( originalFile ), composite, "@", "@" );
-
-                xml = IOUtil.toString( reader );
-
-                reader.close();
-                reader = null;
-            }
-            finally
-            {
-                IOUtil.close( reader );
-            }
-
-            Writer writer = null;
-            try
-            {
-                interpolatedFile.getParentFile().mkdirs();
-                writer = WriterFactory.newXmlWriter( interpolatedFile );
-                writer.write( xml );
-                writer.close();
-                writer = null;
-            }
-            finally
-            {
-                IOUtil.close( writer );
-            }
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( "Failed to interpolate file " + originalFile.getPath(), e );
-        }
-    }
-
-    /**
-     * Gets the (interpolated) invoker properties for an integration test.
-     *
-     * @param projectDirectory The base directory of the IT project, must not be <code>null</code>.
-     * @return The invoker properties, may be empty but never <code>null</code>.
-     * @throws org.apache.maven.plugin.MojoExecutionException If an I/O error occurred during reading the properties.
-     */
-    private InvokerProperties getInvokerProperties( final File projectDirectory )
-        throws MojoExecutionException
-    {
-        Properties props = new Properties();
-        if ( invokerPropertiesFile != null )
-        {
-            File propertiesFile = new File( projectDirectory, invokerPropertiesFile );
-            if ( propertiesFile.isFile() )
-            {
-                InputStream in = null;
-                try
-                {
-                    in = new FileInputStream( propertiesFile );
-                    props.load( in );
-                    in.close();
-                    in = null;
-                }
-                catch ( IOException e )
-                {
-                    throw new MojoExecutionException( "Failed to read invoker properties: " + propertiesFile, e );
-                }
-                finally
-                {
-                    IOUtil.close( in );
-                }
-            }
-
-            Interpolator interpolator = new RegexBasedInterpolator();
-            interpolator.addValueSource( new MapBasedValueSource( getInterpolationValueSource( false ) ) );
-            // CHECKSTYLE_OFF: LineLength
-            for ( String key : props.stringPropertyNames() )
-            {
-                String value = props.getProperty( key );
-                try
-                {
-                    value = interpolator.interpolate( value, "" );
-                }
-                catch ( InterpolationException e )
-                {
-                    throw new MojoExecutionException( "Failed to interpolate invoker properties: " + propertiesFile,
-                                                      e );
-                }
-                props.setProperty( key, value );
-            }
-            // CHECKSTYLE_ON: LineLength
-        }
-        return new InvokerProperties( props );
-    }
-
-    protected boolean isParallelRun()
-    {
-        return parallelThreads > 1;
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.BufferedReader;

+import java.io.BufferedWriter;

+import java.io.File;

+import java.io.FileInputStream;

+import java.io.FileOutputStream;

+import java.io.FileWriter;

+import java.io.IOException;

+import java.io.InputStream;

+import java.io.OutputStreamWriter;

+import java.io.Reader;

+import java.io.Writer;

+import java.text.DecimalFormat;

+import java.text.DecimalFormatSymbols;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.Collection;

+import java.util.Collections;

+import java.util.HashMap;

+import java.util.LinkedHashMap;

+import java.util.LinkedHashSet;

+import java.util.LinkedList;

+import java.util.List;

+import java.util.Locale;

+import java.util.Map;

+import java.util.Map.Entry;

+import java.util.Properties;

+import java.util.StringTokenizer;

+import java.util.TreeSet;

+import java.util.concurrent.ExecutorService;

+import java.util.concurrent.Executors;

+import java.util.concurrent.TimeUnit;

+import org.apache.maven.artifact.Artifact;

+import org.apache.maven.model.Model;

+import org.apache.maven.model.Profile;

+import org.apache.maven.plugin.AbstractMojo;

+import org.apache.maven.plugin.MojoExecution;

+import org.apache.maven.plugin.MojoExecutionException;

+import org.apache.maven.plugin.MojoFailureException;

+import org.apache.maven.plugins.invoker.model.BuildJob;

+import org.apache.maven.plugins.invoker.model.io.xpp3.BuildJobXpp3Writer;

+import org.apache.maven.plugins.annotations.Component;

+import org.apache.maven.plugins.annotations.Parameter;

+import org.apache.maven.project.MavenProject;

+import org.apache.maven.settings.Settings;

+import org.apache.maven.settings.SettingsUtils;

+import org.apache.maven.settings.TrackableBase;

+import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;

+import org.apache.maven.settings.building.SettingsBuilder;

+import org.apache.maven.settings.building.SettingsBuildingException;

+import org.apache.maven.settings.building.SettingsBuildingRequest;

+import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;

+import org.apache.maven.shared.invoker.CommandLineConfigurationException;

+import org.apache.maven.shared.invoker.DefaultInvocationRequest;

+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.MavenCommandLineBuilder;

+import org.apache.maven.shared.invoker.MavenInvocationException;

+import org.apache.maven.shared.scriptinterpreter.RunErrorException;

+import org.apache.maven.shared.scriptinterpreter.RunFailureException;

+import org.apache.maven.shared.scriptinterpreter.ScriptRunner;

+import org.apache.maven.shared.utils.logging.MessageBuilder;

+import org.codehaus.plexus.interpolation.InterpolationException;

+import org.codehaus.plexus.interpolation.Interpolator;

+import org.codehaus.plexus.interpolation.MapBasedValueSource;

+import org.codehaus.plexus.interpolation.RegexBasedInterpolator;

+import org.codehaus.plexus.util.DirectoryScanner;

+import org.codehaus.plexus.util.FileUtils;

+import org.codehaus.plexus.util.IOUtil;

+import org.codehaus.plexus.util.InterpolationFilterReader;

+import org.codehaus.plexus.util.ReaderFactory;

+import org.codehaus.plexus.util.ReflectionUtils;

+import org.codehaus.plexus.util.StringUtils;

+import org.codehaus.plexus.util.WriterFactory;

+import org.codehaus.plexus.util.cli.CommandLineException;

+import org.codehaus.plexus.util.cli.CommandLineUtils;

+import org.codehaus.plexus.util.cli.Commandline;

+import org.codehaus.plexus.util.cli.StreamConsumer;

+import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;

+

+/**

+ * Provides common code for mojos invoking sub builds.

+ *

+ * @author Stephen Connolly

+ * @since 15-Aug-2009 09:09:29

+ */

+public abstract class AbstractInvokerMojo

+    extends AbstractMojo

+{

+    /**

+     * The zero-based column index where to print the invoker result.

+     */

+    private static final int RESULT_COLUMN = 60;

+

+    /**

+     * Flag used to suppress certain invocations. This is useful in tailoring the build using profiles.

+     *

+     * @since 1.1

+     */

+    @Parameter( property = "invoker.skip", defaultValue = "false" )

+    private boolean skipInvocation;

+

+    /**

+     * Flag used to suppress the summary output notifying of successes and failures. If set to <code>true</code>, the

+     * only indication of the build's success or failure will be the effect it has on the main build (if it fails, the

+     * main build should fail as well). If {@link #streamLogs} is enabled, the sub-build summary will also provide an

+     * indication.

+     */

+    @Parameter( defaultValue = "false" )

+    protected boolean suppressSummaries;

+

+    /**

+     * Flag used to determine whether the build logs should be output to the normal mojo log.

+     */

+    @Parameter( property = "invoker.streamLogs", defaultValue = "false" )

+    private boolean streamLogs;

+

+    /**

+     * The local repository for caching artifacts. It is strongly recommended to specify a path to an isolated

+     * repository like <code>${project.build.directory}/it-repo</code>. Otherwise, your ordinary local repository will

+     * be used, potentially soiling it with broken artifacts.

+     */

+    @Parameter( property = "invoker.localRepositoryPath", defaultValue = "${settings.localRepository}" )

+    private File localRepositoryPath;

+

+    /**

+     * Directory to search for integration tests.

+     */

+    @Parameter( property = "invoker.projectsDirectory", defaultValue = "${basedir}/src/it/" )

+    private File projectsDirectory;

+

+    /**

+     * Base directory where all build reports are written to. Every execution of an integration test will produce an XML

+     * file which contains the information about success or failure of that particular build job. The format of the

+     * resulting XML file is documented in the given <a href="./build-job.html">build-job</a> reference.

+     *

+     * @since 1.4

+     */

+    @Parameter( property = "invoker.reportsDirectory", defaultValue = "${project.build.directory}/invoker-reports" )

+    private File reportsDirectory;

+

+    /**

+     * A flag to disable the generation of build reports.

+     *

+     * @since 1.4

+     */

+    @Parameter( property = "invoker.disableReports", defaultValue = "false" )

+    private boolean disableReports;

+

+    /**

+     * Directory to which projects should be cloned prior to execution. If not specified, each integration test will be

+     * run in the directory in which the corresponding IT POM was found. In this case, you most likely want to configure

+     * your SCM to ignore <code>target</code> and <code>build.log</code> in the test's base directory.

+     *

+     * @since 1.1

+     */

+    @Parameter

+    private File cloneProjectsTo;

+

+    // CHECKSTYLE_OFF: LineLength

+    /**

+     * Some files are normally excluded when copying the IT projects from the directory specified by the parameter

+     * projectsDirectory to the directory given by cloneProjectsTo (e.g. <code>.svn</code>, <code>CVS</code>,

+     * <code>*~</code>, etc: see <a href=

+     * "https://codehaus-plexus.github.io/plexus-utils/apidocs/org/codehaus/plexus/util/AbstractScanner.html#DEFAULTEXCLUDES">

+     * reference</a> for full list). Setting this parameter to <code>true</code> will cause all files to be copied to

+     * the <code>cloneProjectsTo</code> directory.

+     *

+     * @since 1.2

+     */

+    @Parameter( defaultValue = "false" )

+    private boolean cloneAllFiles;

+    // CHECKSTYLE_ON: LineLength

+

+    /**

+     * Ensure the {@link #cloneProjectsTo} directory is not polluted with files from earlier invoker runs.

+     *

+     * @since 1.6

+     */

+    @Parameter( defaultValue = "false" )

+    private boolean cloneClean;

+

+    /**

+     * A single POM to build, skipping any scanning parameters and behavior.

+     */

+    @Parameter( property = "invoker.pom" )

+    private File pom;

+

+    /**

+     * Include patterns for searching the integration test directory for projects. This parameter is meant to be set

+     * from the POM. If this parameter is not set, the plugin will search for all <code>pom.xml</code> files one

+     * directory below {@link #projectsDirectory} (i.e. <code>*&#47;pom.xml</code>).<br>

+     * <br>

+     * Starting with version 1.3, mere directories can also be matched by these patterns. For example, the include

+     * pattern <code>*</code> will run Maven builds on all immediate sub directories of {@link #projectsDirectory},

+     * regardless if they contain a <code>pom.xml</code>. This allows to perform builds that need/should not depend on

+     * the existence of a POM.

+     */

+    @Parameter

+    private List<String> pomIncludes = Collections.singletonList( "*/pom.xml" );

+

+    /**

+     * Exclude patterns for searching the integration test directory. This parameter is meant to be set from the POM. By

+     * default, no POM files are excluded. For the convenience of using an include pattern like <code>*</code>, the

+     * custom settings file specified by the parameter {@link #settingsFile} will always be excluded automatically.

+     */

+    @Parameter

+    private List<String> pomExcludes = Collections.emptyList();

+

+    /**

+     * Include patterns for searching the projects directory for projects that need to be run before the other projects.

+     * This parameter allows to declare projects that perform setup tasks like installing utility artifacts into the

+     * local repository. Projects matched by these patterns are implicitly excluded from the scan for ordinary projects.

+     * Also, the exclusions defined by the parameter {@link #pomExcludes} apply to the setup projects, too. Default

+     * value is: <code>setup*&#47;pom.xml</code>.

+     *

+     * @since 1.3

+     */

+    @Parameter

+    private List<String> setupIncludes = Collections.singletonList( "setup*/pom.xml" );

+

+    /**

+     * The list of goals to execute on each project. Default value is: <code>package</code>.

+     */

+    @Parameter

+    private List<String> goals = Collections.singletonList( "package" );

+

+    /**

+     */

+    @Component

+    private Invoker invoker;

+

+    @Component

+    private SettingsBuilder settingsBuilder;

+

+    /**

+     * Relative path of a selector script to run prior in order to decide if the build should be executed. This script

+     * may be written with either BeanShell or Groovy. If the file extension is omitted (e.g. <code>selector</code>),

+     * the plugin searches for the file by trying out the well-known extensions <code>.bsh</code> and

+     * <code>.groovy</code>. If this script exists for a particular project but returns any non-null value different

+     * from <code>true</code>, the corresponding build is flagged as skipped. In this case, none of the pre-build hook

+     * script, Maven nor the post-build hook script will be invoked. If this script throws an exception, the

+     * corresponding build is flagged as in error, and none of the pre-build hook script, Maven not the post-build hook

+     * script will be invoked.

+     *

+     * @since 1.5

+     */

+    @Parameter( property = "invoker.selectorScript", defaultValue = "selector" )

+    private String selectorScript;

+

+    /**

+     * Relative path of a pre-build hook script to run prior to executing the build. This script may be written with

+     * either BeanShell or Groovy (since 1.3). If the file extension is omitted (e.g. <code>prebuild</code>), the plugin

+     * searches for the file by trying out the well-known extensions <code>.bsh</code> and <code>.groovy</code>. If this

+     * script exists for a particular project but returns any non-null value different from <code>true</code> or throws

+     * an exception, the corresponding build is flagged as a failure. In this case, neither Maven nor the post-build

+     * hook script will be invoked.

+     */

+    @Parameter( property = "invoker.preBuildHookScript", defaultValue = "prebuild" )

+    private String preBuildHookScript;

+

+    /**

+     * Relative path of a cleanup/verification hook script to run after executing the build. This script may be written

+     * with either BeanShell or Groovy (since 1.3). If the file extension is omitted (e.g. <code>verify</code>), the

+     * plugin searches for the file by trying out the well-known extensions <code>.bsh</code> and <code>.groovy</code>.

+     * If this script exists for a particular project but returns any non-null value different from <code>true</code> or

+     * throws an exception, the corresponding build is flagged as a failure.

+     */

+    @Parameter( property = "invoker.postBuildHookScript", defaultValue = "postbuild" )

+    private String postBuildHookScript;

+

+    /**

+     * Location of a properties file that defines CLI properties for the test.

+     */

+    @Parameter( property = "invoker.testPropertiesFile", defaultValue = "test.properties" )

+    private String testPropertiesFile;

+

+    /**

+     * Common set of properties to pass in on each project's command line, via -D parameters.

+     *

+     * @since 1.1

+     */

+    @Parameter

+    private Map<String, String> properties;

+

+    /**

+     * Whether to show errors in the build output.

+     */

+    @Parameter( property = "invoker.showErrors", defaultValue = "false" )

+    private boolean showErrors;

+

+    /**

+     * Whether to show debug statements in the build output.

+     */

+    @Parameter( property = "invoker.debug", defaultValue = "false" )

+    private boolean debug;

+

+    /**

+     * Suppress logging to the <code>build.log</code> file.

+     */

+    @Parameter( property = "invoker.noLog", defaultValue = "false" )

+    private boolean noLog;

+

+    /**

+     * List of profile identifiers to explicitly trigger in the build.

+     *

+     * @since 1.1

+     */

+    @Parameter

+    private List<String> profiles;

+

+    /**

+     * A list of additional properties which will be used to filter tokens in POMs and goal files.

+     *

+     * @since 1.3

+     */

+    @Parameter

+    private Map<String, String> filterProperties;

+

+    /**

+     * The Maven Project Object

+     *

+     * @since 1.1

+     */

+    @Parameter( defaultValue = "${project}", readonly = true, required = true )

+    private MavenProject project;

+

+    @Parameter( defaultValue = "${mojoExecution}", readonly = true, required = true )

+    private MojoExecution mojoExecution;

+

+    /**

+     * A comma separated list of projectname patterns to run. Specify this parameter to run individual tests by file

+     * name, overriding the {@link #setupIncludes}, {@link #pomIncludes} and {@link #pomExcludes} parameters. Each

+     * pattern you specify here will be used to create an include/exclude pattern formatted like

+     * <code>${projectsDirectory}/<i>pattern</i></code>. To exclude a test, prefix the pattern with a '<code>!</code>'.

+     * So you can just type <nobr><code>-Dinvoker.test=SimpleTest,Comp*Test,!Compare*</code></nobr> to run builds in

+     * <code>${projectsDirectory}/SimpleTest</code> and <code>${projectsDirectory}/ComplexTest</code>, but not

+     * <code>${projectsDirectory}/CompareTest</code>

+     *

+     * @since 1.1 (exclusion since 1.8)

+     */

+    @Parameter( property = "invoker.test" )

+    private String invokerTest;

+

+    /**

+     * Path to an alternate <code>settings.xml</code> to use for Maven invocation with all ITs. Note that the

+     * <code>&lt;localRepository&gt;</code> element of this settings file is always ignored, i.e. the path given by the

+     * parameter {@link #localRepositoryPath} is dominant.

+     *

+     * @since 1.2

+     */

+    @Parameter( property = "invoker.settingsFile" )

+    private File settingsFile;

+

+    /**

+     * The <code>MAVEN_OPTS</code> environment variable to use when invoking Maven. This value can be overridden for

+     * individual integration tests by using {@link #invokerPropertiesFile}.

+     *

+     * @since 1.2

+     */

+    @Parameter( property = "invoker.mavenOpts" )

+    private String mavenOpts;

+

+    /**

+     * The home directory of the Maven installation to use for the forked builds. Defaults to the current Maven

+     * installation.

+     *

+     * @since 1.3

+     */

+    @Parameter( property = "invoker.mavenHome" )

+    private File mavenHome;

+

+    /**

+     * mavenExecutable can either be a file relative to <code>${maven.home}/bin/</code> or an absolute file.

+     *

+     * @since 1.8

+     * @see Invoker#setMavenExecutable(File)

+     */

+    @Parameter( property = "invoker.mavenExecutable" )

+    private String mavenExecutable;

+

+    /**

+     * The <code>JAVA_HOME</code> environment variable to use for forked Maven invocations. Defaults to the current Java

+     * home directory.

+     *

+     * @since 1.3

+     */

+    @Parameter( property = "invoker.javaHome" )

+    private File javaHome;

+

+    /**

+     * The file encoding for the pre-/post-build scripts and the list files for goals and profiles.

+     *

+     * @since 1.2

+     */

+    @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )

+    private String encoding;

+

+    /**

+     * The current user system settings for use in Maven.

+     *

+     * @since 1.2

+     */

+    @Parameter( defaultValue = "${settings}", readonly = true, required = true )

+    private Settings settings;

+

+    /**

+     * A flag whether the test class path of the project under test should be included in the class path of the

+     * pre-/post-build scripts. If set to <code>false</code>, the class path of script interpreter consists only of the

+     * <a href="dependencies.html">runtime dependencies</a> of the Maven Invoker Plugin. If set the <code>true</code>,

+     * the project's test class path will be prepended to the interpreter class path. Among others, this feature allows

+     * the scripts to access utility classes from the test sources of your project.

+     *

+     * @since 1.2

+     */

+    @Parameter( property = "invoker.addTestClassPath", defaultValue = "false" )

+    private boolean addTestClassPath;

+

+    /**

+     * The test class path of the project under test.

+     */

+    @Parameter( defaultValue = "${project.testClasspathElements}", readonly = true )

+    private List<String> testClassPath;

+

+    /**

+     * The name of an optional project-specific file that contains properties used to specify settings for an individual

+     * Maven invocation. Any property present in the file will override the corresponding setting from the plugin

+     * configuration. The values of the properties are filtered and may use expressions like

+     * <code>${project.version}</code> to reference project properties or values from the parameter

+     * {@link #filterProperties}. The snippet below describes the supported properties:

+     * <p/>

+     *

+     * <pre>

+     * # A comma or space separated list of goals/phases to execute, may

+     * # specify an empty list to execute the default goal of the IT project.

+     * # Environment variables used by maven plugins can be added here

+     * invoker.goals = clean install -Dplugin.variable=value

+     *

+     * # Or you can give things like this if you need.

+     * invoker.goals = -T2 clean verify

+     *

+     * # Optionally, a list of goals to run during further invocations of Maven

+     * invoker.goals.2 = ${project.groupId}:${project.artifactId}:${project.version}:run

+     *

+     * # A comma or space separated list of profiles to activate

+     * invoker.profiles = its,jdk15

+     *

+     * # The path to an alternative POM or base directory to invoke Maven on, defaults to the

+     * # project that was originally specified in the plugin configuration

+     * # Since plugin version 1.4

+     * invoker.project = sub-module

+     *

+     * # The value for the environment variable MAVEN_OPTS

+     * invoker.mavenOpts = -Dfile.encoding=UTF-16 -Xms32m -Xmx256m

+     *

+     * # Possible values are &quot;fail-fast&quot; (default), &quot;fail-at-end&quot; and &quot;fail-never&quot;

+     * invoker.failureBehavior = fail-never

+     *

+     * # The expected result of the build, possible values are &quot;success&quot; (default) and &quot;failure&quot;

+     * invoker.buildResult = failure

+     *

+     * # A boolean value controlling the aggregator mode of Maven, defaults to &quot;false&quot;

+     * invoker.nonRecursive = true

+     *

+     * # A boolean value controlling the network behavior of Maven, defaults to &quot;false&quot;

+     * # Since plugin version 1.4

+     * invoker.offline = true

+     *

+     * # The path to the properties file from which to load system properties, defaults to the

+     * # filename given by the plugin parameter testPropertiesFile

+     * # Since plugin version 1.4

+     * invoker.systemPropertiesFile = test.properties

+     *

+     * # An optional human friendly name for this build job to be included in the build reports.

+     * # Since plugin version 1.4

+     * invoker.name = Test Build 01

+     *

+     * # An optional description for this build job to be included in the build reports.

+     * # Since plugin version 1.4

+     * invoker.description = Checks the support for build reports.

+     *

+     * # A comma separated list of JRE versions on which this build job should be run.

+     * # Since plugin version 1.4

+     * invoker.java.version = 1.4+, !1.4.1, 1.7-

+     * 

+     * # A comma separated list of OS families on which this build job should be run.

+     * # Since plugin version 1.4

+     * invoker.os.family = !windows, unix, mac

+     *

+     * # A comma separated list of Maven versions on which this build should be run.

+     * # Since plugin version 1.5

+     * invoker.maven.version = 2.0.10+, !2.1.0, !2.2.0

+     * 

+     * # For java.version, maven.version and os.family it is possible to define multiple selectors.

+     * # If one of the indexed selectors matches, the test is executed.

+     * # With the invoker.x.y equivalents you can specify global matchers.  

+     * selector.1.java.version = 1.8+

+     * selector.1.maven.version = 3.2.5+

+     * selector.1.os.family = !windows

+     * selector.2.maven.version = 3.0+

+     * selector.3.java.version = 9+

+     * 

+     * # A boolean value controlling the debug logging level of Maven, , defaults to &quot;false&quot;

+     * # Since plugin version 1.8

+     * invoker.debug = true

+     * </pre>

+     *

+     * @since 1.2

+     */

+    @Parameter( property = "invoker.invokerPropertiesFile", defaultValue = "invoker.properties" )

+    private String invokerPropertiesFile;

+

+    /**

+     * flag to enable show mvn version used for running its (cli option : -V,--show-version )

+     *

+     * @since 1.4

+     */

+    @Parameter( property = "invoker.showVersion", defaultValue = "false" )

+    private boolean showVersion;

+

+    /**

+     * number of threads for running tests in parallel. This will be the number of maven forked process in parallel.

+     *

+     * @since 1.6

+     */

+    @Parameter( property = "invoker.parallelThreads", defaultValue = "1" )

+    private int parallelThreads;

+

+    /**

+     * @since 1.6

+     */

+    @Parameter( property = "plugin.artifacts", required = true, readonly = true )

+    private List<Artifact> pluginArtifacts;

+

+    /**

+     * If enable and if you have a settings file configured for the execution, it will be merged with your user

+     * settings.

+     *

+     * @since 1.6

+     */

+    @Parameter( property = "invoker.mergeUserSettings", defaultValue = "false" )

+    private boolean mergeUserSettings;

+

+    /**

+     * Additional environment variables to set on the command line.

+     *

+     * @since 1.8

+     */

+    @Parameter

+    private Map<String, String> environmentVariables;

+

+    /**

+     * Additional variables for use in the hook scripts.

+     *

+     * @since 1.9

+     */

+    @Parameter

+    private Map<String, String> scriptVariables;

+

+    /**

+     * The scripter runner that is responsible to execute hook scripts.

+     */

+    private ScriptRunner scriptRunner;

+

+    /**

+     * A string used to prefix the file name of the filtered POMs in case the POMs couldn't be filtered in-place (i.e.

+     * the projects were not cloned to a temporary directory), can be <code>null</code>. This will be set to

+     * <code>null</code> if the POMs have already been filtered during cloning.

+     */

+    private String filteredPomPrefix = "interpolated-";

+

+    /**

+     * The format for elapsed build time.

+     */

+    private final DecimalFormat secFormat = new DecimalFormat( "(0.0 s)", new DecimalFormatSymbols( Locale.ENGLISH ) );

+

+    /**

+     * The version of Maven which is used to run the builds

+     */

+    private String actualMavenVersion;

+

+    /**

+     * Invokes Maven on the configured test projects.

+     *

+     * @throws org.apache.maven.plugin.MojoExecutionException If the goal encountered severe errors.

+     * @throws org.apache.maven.plugin.MojoFailureException If any of the Maven builds failed.

+     */

+    public void execute()

+        throws MojoExecutionException, MojoFailureException

+    {

+        if ( skipInvocation )

+        {

+            getLog().info( "Skipping invocation per configuration."

+                + " If this is incorrect, ensure the skipInvocation parameter is not set to true." );

+            return;

+        }

+

+        if ( StringUtils.isEmpty( encoding ) )

+        {

+            getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING

+                + ", i.e. build is platform dependent!" );

+        }

+

+        // done it here to prevent issues with concurrent access in case of parallel run

+        if ( !disableReports )

+        {

+            setupReportsFolder();

+        }

+

+        BuildJob[] buildJobs;

+        if ( pom == null )

+        {

+            try

+            {

+                buildJobs = getBuildJobs();

+            }

+            catch ( final IOException e )

+            {

+                throw new MojoExecutionException( "Error retrieving POM list from includes, "

+                    + "excludes, and projects directory. Reason: " + e.getMessage(), e );

+            }

+        }

+        else

+        {

+            try

+            {

+                projectsDirectory = pom.getCanonicalFile().getParentFile();

+            }

+            catch ( IOException e )

+            {

+                throw new MojoExecutionException( "Failed to discover projectsDirectory from "

+                    + "pom File parameter. Reason: " + e.getMessage(), e );

+            }

+

+            buildJobs = new BuildJob[] { new BuildJob( pom.getName(), BuildJob.Type.NORMAL ) };

+        }

+

+        if ( ( buildJobs == null ) || ( buildJobs.length < 1 ) )

+        {

+            doFailIfNoProjects();

+

+            getLog().info( "No projects were selected for execution." );

+            return;

+        }

+

+        handleScriptRunnerWithScriptClassPath();

+

+        Collection<String> collectedProjects = new LinkedHashSet<String>();

+        for ( BuildJob buildJob : buildJobs )

+        {

+            collectProjects( projectsDirectory, buildJob.getProject(), collectedProjects, true );

+        }

+

+        File projectsDir = projectsDirectory;

+

+        if ( cloneProjectsTo != null )

+        {

+            cloneProjects( collectedProjects );

+            projectsDir = cloneProjectsTo;

+        }

+        else

+        {

+            getLog().warn( "Filtering of parent/child POMs is not supported without cloning the projects" );

+        }

+

+        // First run setup jobs.

+        BuildJob[] setupBuildJobs = null;

+        try

+        {

+            setupBuildJobs = getSetupBuildJobsFromFolders();

+        }

+        catch ( IOException e )

+        {

+            getLog().error( "Failure during scanning of folders.", e );

+            // TODO: Check shouldn't we fail in case of problems?

+        }

+

+        if ( setupBuildJobs != null )

+        {

+            // Run setup jobs in single thread

+            // mode.

+            //

+            // Some Idea about ordering?

+            getLog().info( "Running Setup Jobs" );

+            runBuilds( projectsDir, setupBuildJobs, 1 );

+        }

+

+        // Afterwards run all other jobs.

+        BuildJob[] nonSetupBuildJobs = getNonSetupJobs( buildJobs );

+        // We will run the non setup jobs with the configured

+        // parallelThreads number.

+        runBuilds( projectsDir, nonSetupBuildJobs, parallelThreads );

+

+        writeSummaryFile( nonSetupBuildJobs );

+

+        processResults( new InvokerSession( nonSetupBuildJobs ) );

+

+    }

+

+    /**

+     * This will create the necessary folders for the reports.

+     * 

+     * @throws MojoExecutionException in case of failure during creation of the reports folder.

+     */

+    private void setupReportsFolder()

+        throws MojoExecutionException

+    {

+        // If it exists from previous run...

+        if ( reportsDirectory.exists() )

+        {

+            try

+            {

+                FileUtils.deleteDirectory( reportsDirectory );

+            }

+            catch ( IOException e )

+            {

+                throw new MojoExecutionException( "Failure while trying to delete "

+                    + reportsDirectory.getAbsolutePath(), e );

+            }

+        }

+        if ( !reportsDirectory.mkdirs() )

+        {

+            throw new MojoExecutionException( "Failure while creating the " + reportsDirectory.getAbsolutePath() );

+        }

+    }

+

+    private BuildJob[] getNonSetupJobs( BuildJob[] buildJobs )

+    {

+        List<BuildJob> result = new LinkedList<BuildJob>();

+        for ( int i = 0; i < buildJobs.length; i++ )

+        {

+            if ( !buildJobs[i].getType().equals( BuildJob.Type.SETUP ) )

+            {

+                result.add( buildJobs[i] );

+            }

+        }

+        BuildJob[] buildNonSetupJobs = result.toArray( new BuildJob[result.size()] );

+        return buildNonSetupJobs;

+    }

+

+    private void handleScriptRunnerWithScriptClassPath()

+    {

+        final List<String> scriptClassPath;

+        if ( addTestClassPath )

+        {

+            scriptClassPath = new ArrayList<String>( testClassPath );

+            for ( Artifact pluginArtifact : pluginArtifacts )

+            {

+                scriptClassPath.remove( pluginArtifact.getFile().getAbsolutePath() );

+            }

+        }

+        else

+        {

+            scriptClassPath = null;

+        }

+        scriptRunner = new ScriptRunner( getLog() );

+        scriptRunner.setScriptEncoding( encoding );

+        scriptRunner.setGlobalVariable( "localRepositoryPath", localRepositoryPath );

+        if ( scriptVariables != null )

+        {

+            for ( Entry<String, String> entry : scriptVariables.entrySet() )

+            {

+                scriptRunner.setGlobalVariable( entry.getKey(), entry.getValue() );

+            }

+        }

+        scriptRunner.setClassPath( scriptClassPath );

+    }

+

+    private void writeSummaryFile( BuildJob[] buildJobs )

+        throws MojoExecutionException

+    {

+

+        File summaryReportFile = new File( reportsDirectory, "invoker-summary.txt" );

+

+        try

+        {

+            Writer writer = new BufferedWriter( new FileWriter( summaryReportFile ) );

+

+            for ( int i = 0; i < buildJobs.length; i++ )

+            {

+                BuildJob buildJob = buildJobs[i];

+                if ( !buildJob.getResult().equals( BuildJob.Result.SUCCESS ) )

+                {

+                    writer.append( buildJob.getResult() );

+                    writer.append( " [" );

+                    writer.append( buildJob.getProject() );

+                    writer.append( "] " );

+                    if ( buildJob.getFailureMessage() != null )

+                    {

+                        writer.append( " " );

+                        writer.append( buildJob.getFailureMessage() );

+                    }

+                    writer.append( "\n" );

+                }

+            }

+

+            writer.close();

+        }

+        catch ( IOException e )

+        {

+            throw new MojoExecutionException( "Failed to write summary report " + summaryReportFile, e );

+        }

+    }

+

+    protected void doFailIfNoProjects()

+        throws MojoFailureException

+    {

+        // should only be used during run and verify

+    }

+

+    /**

+     * Processes the results of invoking the build jobs.

+     *

+     * @param invokerSession The session with the build jobs, must not be <code>null</code>.

+     * @throws MojoFailureException If the mojo had failed as a result of invoking the build jobs.

+     * @since 1.4

+     */

+    abstract void processResults( InvokerSession invokerSession )

+        throws MojoFailureException;

+

+    /**

+     * Creates a new reader for the specified file, using the plugin's {@link #encoding} parameter.

+     *

+     * @param file The file to create a reader for, must not be <code>null</code>.

+     * @return The reader for the file, never <code>null</code>.

+     * @throws java.io.IOException If the specified file was not found or the configured encoding is not supported.

+     */

+    private Reader newReader( File file )

+        throws IOException

+    {

+        if ( StringUtils.isNotEmpty( encoding ) )

+        {

+            return ReaderFactory.newReader( file, encoding );

+        }

+        else

+        {

+            return ReaderFactory.newPlatformReader( file );

+        }

+    }

+

+    /**

+     * Collects all projects locally reachable from the specified project. The method will as such try to read the POM

+     * and recursively follow its parent/module elements.

+     *

+     * @param projectsDir The base directory of all projects, must not be <code>null</code>.

+     * @param projectPath The relative path of the current project, can denote either the POM or its base directory,

+     *            must not be <code>null</code>.

+     * @param projectPaths The set of already collected projects to add new projects to, must not be <code>null</code>.

+     *            This set will hold the relative paths to either a POM file or a project base directory.

+     * @param included A flag indicating whether the specified project has been explicitly included via the parameter

+     *            {@link #pomIncludes}. Such projects will always be added to the result set even if there is no

+     *            corresponding POM.

+     * @throws org.apache.maven.plugin.MojoExecutionException If the project tree could not be traversed.

+     */

+    private void collectProjects( File projectsDir, String projectPath, Collection<String> projectPaths,

+                                  boolean included )

+        throws MojoExecutionException

+    {

+        projectPath = projectPath.replace( '\\', '/' );

+        File pomFile = new File( projectsDir, projectPath );

+        if ( pomFile.isDirectory() )

+        {

+            pomFile = new File( pomFile, "pom.xml" );

+            if ( !pomFile.exists() )

+            {

+                if ( included )

+                {

+                    projectPaths.add( projectPath );

+                }

+                return;

+            }

+            if ( !projectPath.endsWith( "/" ) )

+            {

+                projectPath += '/';

+            }

+            projectPath += "pom.xml";

+        }

+        else if ( !pomFile.isFile() )

+        {

+            return;

+        }

+        if ( !projectPaths.add( projectPath ) )

+        {

+            return;

+        }

+        getLog().debug( "Collecting parent/child projects of " + projectPath );

+

+        Model model = PomUtils.loadPom( pomFile );

+

+        try

+        {

+            String projectsRoot = projectsDir.getCanonicalPath();

+            String projectDir = pomFile.getParent();

+

+            String parentPath = "../pom.xml";

+            if ( model.getParent() != null && StringUtils.isNotEmpty( model.getParent().getRelativePath() ) )

+            {

+                parentPath = model.getParent().getRelativePath();

+            }

+            String parent = relativizePath( new File( projectDir, parentPath ), projectsRoot );

+            if ( parent != null )

+            {

+                collectProjects( projectsDir, parent, projectPaths, false );

+            }

+

+            Collection<String> modulePaths = new LinkedHashSet<String>();

+

+            modulePaths.addAll( model.getModules() );

+

+            for ( Profile profile : model.getProfiles() )

+            {

+                modulePaths.addAll( profile.getModules() );

+            }

+

+            for ( String modulePath : modulePaths )

+            {

+                String module = relativizePath( new File( projectDir, modulePath ), projectsRoot );

+                if ( module != null )

+                {

+                    collectProjects( projectsDir, module, projectPaths, false );

+                }

+            }

+        }

+        catch ( IOException e )

+        {

+            throw new MojoExecutionException( "Failed to analyze POM: " + pomFile, e );

+        }

+    }

+

+    /**

+     * Copies the specified projects to the directory given by {@link #cloneProjectsTo}. A project may either be denoted

+     * by a path to a POM file or merely by a path to a base directory. During cloning, the POM files will be filtered.

+     *

+     * @param projectPaths The paths to the projects to clone, relative to the projects directory, must not be

+     *            <code>null</code> nor contain <code>null</code> elements.

+     * @throws org.apache.maven.plugin.MojoExecutionException If the the projects could not be copied/filtered.

+     */

+    private void cloneProjects( Collection<String> projectPaths )

+        throws MojoExecutionException

+    {

+        if ( !cloneProjectsTo.mkdirs() && cloneClean )

+        {

+            try

+            {

+                FileUtils.cleanDirectory( cloneProjectsTo );

+            }

+            catch ( IOException e )

+            {

+                throw new MojoExecutionException( "Could not clean the cloneProjectsTo directory. Reason: "

+                    + e.getMessage(), e );

+            }

+        }

+

+        // determine project directories to clone

+        Collection<String> dirs = new LinkedHashSet<String>();

+        for ( String projectPath : projectPaths )

+        {

+            if ( !new File( projectsDirectory, projectPath ).isDirectory() )

+            {

+                projectPath = getParentPath( projectPath );

+            }

+            dirs.add( projectPath );

+        }

+

+        boolean filter;

+

+        // clone project directories

+        try

+        {

+            filter = !cloneProjectsTo.getCanonicalFile().equals( projectsDirectory.getCanonicalFile() );

+

+            List<String> clonedSubpaths = new ArrayList<String>();

+

+            for ( String subpath : dirs )

+            {

+                // skip this project if its parent directory is also scheduled for cloning

+                if ( !".".equals( subpath ) && dirs.contains( getParentPath( subpath ) ) )

+                {

+                    continue;

+                }

+

+                // avoid copying subdirs that are already cloned.

+                if ( !alreadyCloned( subpath, clonedSubpaths ) )

+                {

+                    // avoid creating new files that point to dir/.

+                    if ( ".".equals( subpath ) )

+                    {

+                        String cloneSubdir = relativizePath( cloneProjectsTo, projectsDirectory.getCanonicalPath() );

+

+                        // avoid infinite recursion if the cloneTo path is a subdirectory.

+                        if ( cloneSubdir != null )

+                        {

+                            File temp = File.createTempFile( "pre-invocation-clone.", "" );

+                            temp.delete();

+                            temp.mkdirs();

+

+                            copyDirectoryStructure( projectsDirectory, temp );

+

+                            FileUtils.deleteDirectory( new File( temp, cloneSubdir ) );

+

+                            copyDirectoryStructure( temp, cloneProjectsTo );

+                        }

+                        else

+                        {

+                            copyDirectoryStructure( projectsDirectory, cloneProjectsTo );

+                        }

+                    }

+                    else

+                    {

+                        File srcDir = new File( projectsDirectory, subpath );

+                        File dstDir = new File( cloneProjectsTo, subpath );

+                        copyDirectoryStructure( srcDir, dstDir );

+                    }

+

+                    clonedSubpaths.add( subpath );

+                }

+            }

+        }

+        catch ( IOException e )

+        {

+            throw new MojoExecutionException( "Failed to clone projects from: " + projectsDirectory + " to: "

+                + cloneProjectsTo + ". Reason: " + e.getMessage(), e );

+        }

+

+        // filter cloned POMs

+        if ( filter )

+        {

+            for ( String projectPath : projectPaths )

+            {

+                File pomFile = new File( cloneProjectsTo, projectPath );

+                if ( pomFile.isFile() )

+                {

+                    buildInterpolatedFile( pomFile, pomFile );

+                }

+

+                // MINVOKER-186

+                // The following is a temporary solution to support Maven 3.3.1 (.mvn/extensions.xml) filtering

+                // Will be replaced by MINVOKER-117 with general filtering mechanism

+                File baseDir = pomFile.getParentFile();

+                File mvnDir = new File( baseDir, ".mvn" );

+                if ( mvnDir.isDirectory() )

+                {

+                    File extensionsFile = new File( mvnDir, "extensions.xml" );

+                    if ( extensionsFile.isFile() )

+                    {

+                        buildInterpolatedFile( extensionsFile, extensionsFile );

+                    }

+                }

+                // END MINVOKER-186

+            }

+            filteredPomPrefix = null;

+        }

+    }

+

+    /**

+     * Gets the parent path of the specified relative path.

+     *

+     * @param path The relative path whose parent should be retrieved, must not be <code>null</code>.

+     * @return The parent path or "." if the specified path has no parent, never <code>null</code>.

+     */

+    private String getParentPath( String path )

+    {

+        int lastSep = Math.max( path.lastIndexOf( '/' ), path.lastIndexOf( '\\' ) );

+        return ( lastSep < 0 ) ? "." : path.substring( 0, lastSep );

+    }

+

+    /**

+     * Copied a directory structure with default exclusions (.svn, CVS, etc)

+     *

+     * @param sourceDir The source directory to copy, must not be <code>null</code>.

+     * @param destDir The target directory to copy to, must not be <code>null</code>.

+     * @throws java.io.IOException If the directory structure could not be copied.

+     */

+    private void copyDirectoryStructure( File sourceDir, File destDir )

+        throws IOException

+    {

+        DirectoryScanner scanner = new DirectoryScanner();

+        scanner.setBasedir( sourceDir );

+        if ( !cloneAllFiles )

+        {

+            scanner.addDefaultExcludes();

+        }

+        scanner.scan();

+

+        /*

+         * NOTE: Make sure the destination directory is always there (even if empty) to support POM-less ITs.

+         */

+        destDir.mkdirs();

+        // Create all the directories, including any symlinks present in source

+        FileUtils.mkDirs( sourceDir, scanner.getIncludedDirectories(), destDir );

+

+        for ( String includedFile : scanner.getIncludedFiles() )

+        {

+            File sourceFile = new File( sourceDir, includedFile );

+            File destFile = new File( destDir, includedFile );

+            FileUtils.copyFile( sourceFile, destFile );

+

+            // ensure clone project must be writable for additional changes

+            destFile.setWritable( true );

+        }

+    }

+

+    /**

+     * Determines whether the specified sub path has already been cloned, i.e. whether one of its ancestor directories

+     * was already cloned.

+     *

+     * @param subpath The sub path to check, must not be <code>null</code>.

+     * @param clonedSubpaths The list of already cloned paths, must not be <code>null</code> nor contain

+     *            <code>null</code> elements.

+     * @return <code>true</code> if the specified path has already been cloned, <code>false</code> otherwise.

+     */

+    static boolean alreadyCloned( String subpath, List<String> clonedSubpaths )

+    {

+        for ( String path : clonedSubpaths )

+        {

+            if ( ".".equals( path ) || subpath.equals( path ) || subpath.startsWith( path + File.separator ) )

+            {

+                return true;

+            }

+        }

+

+        return false;

+    }

+

+    /**

+     * Runs the specified build jobs.

+     *

+     * @param projectsDir The base directory of all projects, must not be <code>null</code>.

+     * @param buildJobs The build jobs to run must not be <code>null</code> nor contain <code>null</code> elements.

+     * @throws org.apache.maven.plugin.MojoExecutionException If any build could not be launched.

+     */

+    private void runBuilds( final File projectsDir, BuildJob[] buildJobs, int runWithParallelThreads )

+        throws MojoExecutionException

+    {

+        if ( !localRepositoryPath.exists() )

+        {

+            localRepositoryPath.mkdirs();

+        }

+

+        // -----------------------------------------------

+        // interpolate settings file

+        // -----------------------------------------------

+

+        File interpolatedSettingsFile = interpolateSettings();

+

+        final File mergedSettingsFile = mergeSettings( interpolatedSettingsFile );

+

+        if ( mavenHome != null )

+        {

+            actualMavenVersion = SelectorUtils.getMavenVersion( mavenHome );

+        }

+        else

+        {

+            actualMavenVersion = SelectorUtils.getMavenVersion();

+        }

+        scriptRunner.setGlobalVariable( "mavenVersion", actualMavenVersion );

+

+        final CharSequence actualJreVersion;

+        // @todo if ( javaVersions ) ... to be picked up from toolchains

+        if ( javaHome != null )

+        {

+            actualJreVersion = resolveExternalJreVersion();

+        }

+        else

+        {

+            actualJreVersion = SelectorUtils.getJreVersion();

+        }

+

+        try

+        {

+            if ( runWithParallelThreads > 1 )

+            {

+                getLog().info( "use parallelThreads " + runWithParallelThreads );

+

+                ExecutorService executorService = Executors.newFixedThreadPool( runWithParallelThreads );

+                for ( final BuildJob job : buildJobs )

+                {

+                    executorService.execute( new Runnable()

+                    {

+                        public void run()

+                        {

+                            try

+                            {

+                                runBuild( projectsDir, job, mergedSettingsFile, javaHome, actualJreVersion );

+                            }

+                            catch ( MojoExecutionException e )

+                            {

+                                throw new RuntimeException( e.getMessage(), e );

+                            }

+                        }

+                    } );

+                }

+

+                try

+                {

+                    executorService.shutdown();

+                    // TODO add a configurable time out

+                    executorService.awaitTermination( Long.MAX_VALUE, TimeUnit.MILLISECONDS );

+                }

+                catch ( InterruptedException e )

+                {

+                    throw new MojoExecutionException( e.getMessage(), e );

+                }

+            }

+            else

+            {

+                for ( BuildJob job : buildJobs )

+                {

+                    runBuild( projectsDir, job, mergedSettingsFile, javaHome, actualJreVersion );

+                }

+            }

+        }

+        finally

+        {

+            if ( interpolatedSettingsFile != null && cloneProjectsTo == null )

+            {

+                interpolatedSettingsFile.delete();

+            }

+            if ( mergedSettingsFile != null && mergedSettingsFile.exists() )

+            {

+                mergedSettingsFile.delete();

+            }

+        }

+    }

+

+    /**

+     * Interpolate settings.xml file.

+     * 

+     * @return The interpolated settings.xml file.

+     * @throws MojoExecutionException in case of a problem.

+     */

+    private File interpolateSettings()

+        throws MojoExecutionException

+    {

+        File interpolatedSettingsFile = null;

+        if ( settingsFile != null )

+        {

+            if ( cloneProjectsTo != null )

+            {

+                interpolatedSettingsFile = new File( cloneProjectsTo, "interpolated-" + settingsFile.getName() );

+            }

+            else

+            {

+                interpolatedSettingsFile =

+                    new File( settingsFile.getParentFile(), "interpolated-" + settingsFile.getName() );

+            }

+            buildInterpolatedFile( settingsFile, interpolatedSettingsFile );

+        }

+        return interpolatedSettingsFile;

+    }

+

+    /**

+     * Merge the settings file

+     * 

+     * @param interpolatedSettingsFile The interpolated settings file.

+     * @return The merged settings file.

+     * @throws MojoExecutionException Fail the build in case the merged settings file can't be created.

+     */

+    private File mergeSettings( File interpolatedSettingsFile )

+        throws MojoExecutionException

+    {

+        File mergedSettingsFile;

+        Settings mergedSettings = this.settings;

+        if ( mergeUserSettings )

+        {

+            if ( interpolatedSettingsFile != null )

+            {

+                // Have to merge the specified settings file (dominant) and the one of the invoking Maven process

+                try

+                {

+                    SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();

+                    request.setGlobalSettingsFile( interpolatedSettingsFile );

+

+                    Settings dominantSettings = settingsBuilder.build( request ).getEffectiveSettings();

+                    Settings recessiveSettings = cloneSettings();

+                    SettingsUtils.merge( dominantSettings, recessiveSettings, TrackableBase.USER_LEVEL );

+

+                    mergedSettings = dominantSettings;

+                    getLog().debug( "Merged specified settings file with settings of invoking process" );

+                }

+                catch ( SettingsBuildingException e )

+                {

+                    throw new MojoExecutionException( "Could not read specified settings file", e );

+                }

+            }

+        }

+

+        if ( this.settingsFile != null && !mergeUserSettings )

+        {

+            mergedSettingsFile = interpolatedSettingsFile;

+        }

+        else

+        {

+            try

+            {

+                mergedSettingsFile = writeMergedSettingsFile( mergedSettings );

+            }

+            catch ( IOException e )

+            {

+                throw new MojoExecutionException( "Could not create temporary file for invoker settings.xml", e );

+            }

+        }

+        return mergedSettingsFile;

+    }

+

+    private File writeMergedSettingsFile( Settings mergedSettings )

+        throws IOException

+    {

+        File mergedSettingsFile;

+        mergedSettingsFile = File.createTempFile( "invoker-settings", ".xml" );

+

+        SettingsXpp3Writer settingsWriter = new SettingsXpp3Writer();

+

+        FileWriter fileWriter = null;

+        try

+        {

+            fileWriter = new FileWriter( mergedSettingsFile );

+            settingsWriter.write( fileWriter, mergedSettings );

+            fileWriter.close();

+            fileWriter = null;

+        }

+        finally

+        {

+            IOUtil.close( fileWriter );

+        }

+

+        if ( getLog().isDebugEnabled() )

+        {

+            getLog().debug( "Created temporary file for invoker settings.xml: "

+                + mergedSettingsFile.getAbsolutePath() );

+        }

+        return mergedSettingsFile;

+    }

+

+    private Settings cloneSettings()

+    {

+        Settings recessiveSettings = SettingsUtils.copySettings( this.settings );

+

+        // MINVOKER-133: reset sourceLevelSet

+        resetSourceLevelSet( recessiveSettings );

+        for ( org.apache.maven.settings.Mirror mirror : recessiveSettings.getMirrors() )

+        {

+            resetSourceLevelSet( mirror );

+        }

+        for ( org.apache.maven.settings.Server server : recessiveSettings.getServers() )

+        {

+            resetSourceLevelSet( server );

+        }

+        for ( org.apache.maven.settings.Proxy proxy : recessiveSettings.getProxies() )

+        {

+            resetSourceLevelSet( proxy );

+        }

+        for ( org.apache.maven.settings.Profile profile : recessiveSettings.getProfiles() )

+        {

+            resetSourceLevelSet( profile );

+        }

+

+        return recessiveSettings;

+    }

+

+    private void resetSourceLevelSet( org.apache.maven.settings.TrackableBase trackable )

+    {

+        try

+        {

+            ReflectionUtils.setVariableValueInObject( trackable, "sourceLevelSet", Boolean.FALSE );

+            getLog().debug( "sourceLevelSet: "

+                + ReflectionUtils.getValueIncludingSuperclasses( "sourceLevelSet", trackable ) );

+        }

+        catch ( IllegalAccessException e )

+        {

+            // noop

+        }

+    }

+

+    private CharSequence resolveExternalJreVersion()

+    {

+        Artifact pluginArtifact = mojoExecution.getMojoDescriptor().getPluginDescriptor().getPluginArtifact();

+        pluginArtifact.getFile();

+

+        Commandline commandLine = new Commandline();

+        commandLine.setExecutable( new File( javaHome, "bin/java" ).getAbsolutePath() );

+        commandLine.createArg().setValue( "-cp" );

+        commandLine.createArg().setFile( pluginArtifact.getFile() );

+        commandLine.createArg().setValue( SystemPropertyPrinter.class.getName() );

+        commandLine.createArg().setValue( "java.version" );

+

+        final StringBuilder actualJreVersion = new StringBuilder();

+        StreamConsumer consumer = new StreamConsumer()

+        {

+            public void consumeLine( String line )

+            {

+                actualJreVersion.append( line );

+            }

+        };

+        try

+        {

+            CommandLineUtils.executeCommandLine( commandLine, consumer, null );

+        }

+        catch ( CommandLineException e )

+        {

+            getLog().warn( e.getMessage() );

+        }

+        return actualJreVersion;

+    }

+

+    /**

+     * Interpolate the pom file.

+     * 

+     * @param pomFile The pom file.

+     * @param basedir The base directory.

+     * @return interpolated pom file location in case we have interpolated the pom file otherwise the original pom file

+     *         will be returned.

+     * @throws MojoExecutionException

+     */

+    private File interpolatePomFile( File pomFile, File basedir )

+        throws MojoExecutionException

+    {

+        File interpolatedPomFile = null;

+        if ( pomFile != null )

+        {

+            if ( StringUtils.isNotEmpty( filteredPomPrefix ) )

+            {

+                interpolatedPomFile = new File( basedir, filteredPomPrefix + pomFile.getName() );

+                buildInterpolatedFile( pomFile, interpolatedPomFile );

+            }

+            else

+            {

+                interpolatedPomFile = pomFile;

+            }

+        }

+        return interpolatedPomFile;

+    }

+

+    /**

+     * Runs the specified project.

+     *

+     * @param projectsDir The base directory of all projects, must not be <code>null</code>.

+     * @param buildJob The build job to run, must not be <code>null</code>.

+     * @param settingsFile The (already interpolated) user settings file for the build, may be <code>null</code> to use

+     *            the current user settings.

+     * @throws org.apache.maven.plugin.MojoExecutionException If the project could not be launched.

+     */

+    private void runBuild( File projectsDir, BuildJob buildJob, File settingsFile, File actualJavaHome,

+                           CharSequence actualJreVersion )

+        throws MojoExecutionException

+    {

+        // FIXME: Think about the following code part -- START

+        File pomFile = new File( projectsDir, buildJob.getProject() );

+        File basedir;

+        if ( pomFile.isDirectory() )

+        {

+            basedir = pomFile;

+            pomFile = new File( basedir, "pom.xml" );

+            if ( !pomFile.exists() )

+            {

+                pomFile = null;

+            }

+            else

+            {

+                buildJob.setProject( buildJob.getProject() + File.separator + "pom.xml" );

+            }

+        }

+        else

+        {

+            basedir = pomFile.getParentFile();

+        }

+

+        File interpolatedPomFile = interpolatePomFile( pomFile, basedir );

+        // FIXME: Think about the following code part -- ^^^^^^^ END

+

+        getLog().info( buffer().a( "Building: " ).strong( buildJob.getProject() ).toString() );

+

+        InvokerProperties invokerProperties = getInvokerProperties( basedir );

+

+        // let's set what details we can

+        buildJob.setName( invokerProperties.getJobName() );

+        buildJob.setDescription( invokerProperties.getJobDescription() );

+

+        try

+        {

+            int selection = getSelection( invokerProperties, actualJreVersion );

+            if ( selection == 0 )

+            {

+                long milliseconds = System.currentTimeMillis();

+                boolean executed;

+                try

+                {

+                    // CHECKSTYLE_OFF: LineLength

+                    executed =

+                        runBuild( basedir, interpolatedPomFile, settingsFile, actualJavaHome, invokerProperties );

+                    // CHECKSTYLE_ON: LineLength

+                }

+                finally

+                {

+                    milliseconds = System.currentTimeMillis() - milliseconds;

+                    buildJob.setTime( milliseconds / 1000.0 );

+                }

+

+                if ( executed )

+                {

+                    buildJob.setResult( BuildJob.Result.SUCCESS );

+

+                    if ( !suppressSummaries )

+                    {

+                        getLog().info( pad( buildJob ).success( "SUCCESS" ).a( ' ' )

+                            + formatTime( buildJob.getTime() ) );

+                    }

+                }

+                else

+                {

+                    buildJob.setResult( BuildJob.Result.SKIPPED );

+

+                    if ( !suppressSummaries )

+                    {

+                        getLog().info( pad( buildJob ).warning( "SKIPPED" ).a( ' ' )

+                            + formatTime( buildJob.getTime() ) );

+                    }

+                }

+            }

+            else

+            {

+                buildJob.setResult( BuildJob.Result.SKIPPED );

+

+                StringBuilder message = new StringBuilder();

+                if ( selection == Selector.SELECTOR_MULTI )

+                {

+                    message.append( "non-matching selectors" );

+                }

+                else

+                {

+                    if ( ( selection & Selector.SELECTOR_MAVENVERSION ) != 0 )

+                    {

+                        message.append( "Maven version" );

+                    }

+                    if ( ( selection & Selector.SELECTOR_JREVERSION ) != 0 )

+                    {

+                        if ( message.length() > 0 )

+                        {

+                            message.append( ", " );

+                        }

+                        message.append( "JRE version" );

+                    }

+                    if ( ( selection & Selector.SELECTOR_OSFAMILY ) != 0 )

+                    {

+                        if ( message.length() > 0 )

+                        {

+                            message.append( ", " );

+                        }

+                        message.append( "OS" );

+                    }

+                }

+

+                if ( !suppressSummaries )

+                {

+                    getLog().info( pad( buildJob ).warning( "SKIPPED" ) + " due to " + message.toString() );

+                }

+

+                // Abuse failureMessage, the field in the report which should contain the reason for skipping

+                // Consider skipCode + I18N

+                buildJob.setFailureMessage( "Skipped due to " + message.toString() );

+            }

+        }

+        catch ( RunErrorException e )

+        {

+            buildJob.setResult( BuildJob.Result.ERROR );

+            buildJob.setFailureMessage( e.getMessage() );

+

+            if ( !suppressSummaries )

+            {

+                getLog().info( pad( buildJob ).failure( "ERROR" ).a( ' ' ) + formatTime( buildJob.getTime() ) );

+                getLog().info( "  " + e.getMessage() );

+            }

+        }

+        catch ( RunFailureException e )

+        {

+            buildJob.setResult( e.getType() );

+            buildJob.setFailureMessage( e.getMessage() );

+

+            if ( !suppressSummaries )

+            {

+                getLog().info( pad( buildJob ).failure( "FAILED" ).a( ' ' ) + formatTime( buildJob.getTime() ) );

+                getLog().info( "  " + e.getMessage() );

+            }

+        }

+        finally

+        {

+            deleteInterpolatedPomFile( interpolatedPomFile );

+            writeBuildReport( buildJob );

+        }

+    }

+

+    private MessageBuilder pad( BuildJob buildJob )

+    {

+        MessageBuilder buffer = buffer( 128 );

+

+        buffer.a( "          " );

+        buffer.a( buildJob.getProject() );

+        buffer.a( ' ' );

+

+        int l = 11 + buildJob.getProject().length();

+

+        if ( l < RESULT_COLUMN )

+        {

+            for ( int i = RESULT_COLUMN - l; i > 0; i-- )

+            {

+                buffer.a( '.' );

+            }

+        }

+

+        return buffer.a( ' ' );

+    }

+

+    /**

+     * Delete the interpolated pom file if it has been created before.

+     * 

+     * @param interpolatedPomFile The interpolated pom file.

+     */

+    private void deleteInterpolatedPomFile( File interpolatedPomFile )

+    {

+        if ( interpolatedPomFile != null && StringUtils.isNotEmpty( filteredPomPrefix ) )

+        {

+            interpolatedPomFile.delete();

+        }

+    }

+

+    /**

+     * Determines whether selector conditions of the specified invoker properties match the current environment.

+     *

+     * @param invokerProperties The invoker properties to check, must not be <code>null</code>.

+     * @return <code>0</code> if the job corresponding to the properties should be run, otherwise a bitwise value

+     *         representing the reason why it should be skipped.

+     */

+    private int getSelection( InvokerProperties invokerProperties, CharSequence actualJreVersion )

+    {

+        return new Selector( actualMavenVersion, actualJreVersion.toString() ).getSelection( invokerProperties );

+    }

+

+    /**

+     * Writes the XML report for the specified build job unless report generation has been disabled.

+     *

+     * @param buildJob The build job whose report should be written, must not be <code>null</code>.

+     * @throws org.apache.maven.plugin.MojoExecutionException If the report could not be written.

+     */

+    private void writeBuildReport( BuildJob buildJob )

+        throws MojoExecutionException

+    {

+        if ( disableReports )

+        {

+            return;

+        }

+

+        String safeFileName = buildJob.getProject().replace( '/', '_' ).replace( '\\', '_' ).replace( ' ', '_' );

+        if ( safeFileName.endsWith( "_pom.xml" ) )

+        {

+            safeFileName = safeFileName.substring( 0, safeFileName.length() - "_pom.xml".length() );

+        }

+

+        File reportFile = new File( reportsDirectory, "BUILD-" + safeFileName + ".xml" );

+        try

+        {

+            FileOutputStream fos = new FileOutputStream( reportFile );

+            try

+            {

+                Writer osw = new OutputStreamWriter( fos, buildJob.getModelEncoding() );

+                BuildJobXpp3Writer writer = new BuildJobXpp3Writer();

+                writer.write( osw, buildJob );

+                osw.close();

+            }

+            finally

+            {

+                fos.close();

+            }

+        }

+        catch ( IOException e )

+        {

+            throw new MojoExecutionException( "Failed to write build report " + reportFile, e );

+        }

+    }

+

+    /**

+     * Formats the specified build duration time.

+     *

+     * @param seconds The duration of the build.

+     * @return The formatted time, never <code>null</code>.

+     */

+    private String formatTime( double seconds )

+    {

+        return secFormat.format( seconds );

+    }

+

+    /**

+     * Runs the specified project.

+     *

+     * @param basedir The base directory of the project, must not be <code>null</code>.

+     * @param pomFile The (already interpolated) POM file, may be <code>null</code> for a POM-less Maven invocation.

+     * @param settingsFile The (already interpolated) user settings file for the build, may be <code>null</code>. Will

+     *            be merged with the settings file of the invoking Maven process.

+     * @param invokerProperties The properties to use.

+     * @return <code>true</code> if the project was launched or <code>false</code> if the selector script indicated that

+     *         the project should be skipped.

+     * @throws org.apache.maven.plugin.MojoExecutionException If the project could not be launched.

+     * @throws org.apache.maven.shared.scriptinterpreter.RunFailureException If either a hook script or the build itself

+     *             failed.

+     */

+    private boolean runBuild( File basedir, File pomFile, File settingsFile, File actualJavaHome,

+                              InvokerProperties invokerProperties )

+        throws MojoExecutionException, RunFailureException

+    {

+        if ( getLog().isDebugEnabled() && !invokerProperties.getProperties().isEmpty() )

+        {

+            Properties props = invokerProperties.getProperties();

+            getLog().debug( "Using invoker properties:" );

+            for ( String key : new TreeSet<String>( props.stringPropertyNames() ) )

+            {

+                String value = props.getProperty( key );

+                getLog().debug( "  " + key + " = " + value );

+            }

+        }

+

+        List<String> goals = getGoals( basedir );

+

+        List<String> profiles = getProfiles( basedir );

+

+        Map<String, Object> context = new LinkedHashMap<String, Object>();

+

+        FileLogger logger = setupBuildLogFile( basedir );

+        try

+        {

+            try

+            {

+                scriptRunner.run( "selector script", basedir, selectorScript, context, logger, BuildJob.Result.SKIPPED,

+                                  false );

+            }

+            catch ( RunErrorException e )

+            {

+                throw e;

+            }

+            catch ( RunFailureException e )

+            {

+                return false;

+            }

+

+            scriptRunner.run( "pre-build script", basedir, preBuildHookScript, context, logger,

+                              BuildJob.Result.FAILURE_PRE_HOOK, false );

+

+            final InvocationRequest request = new DefaultInvocationRequest();

+

+            request.setLocalRepositoryDirectory( localRepositoryPath );

+

+            request.setBatchMode( true );

+

+            request.setShowErrors( showErrors );

+

+            request.setDebug( debug );

+

+            request.setShowVersion( showVersion );

+

+            setupLoggerForBuildJob( logger, request );

+

+            if ( mavenHome != null )

+            {

+                invoker.setMavenHome( mavenHome );

+                // FIXME: Should we really take care of M2_HOME?

+                request.addShellEnvironment( "M2_HOME", mavenHome.getAbsolutePath() );

+            }

+

+            if ( mavenExecutable != null )

+            {

+                invoker.setMavenExecutable( new File( mavenExecutable ) );

+            }

+

+            if ( actualJavaHome != null )

+            {

+                request.setJavaHome( actualJavaHome );

+            }

+

+            if ( environmentVariables != null )

+            {

+                for ( Map.Entry<String, String> variable : environmentVariables.entrySet() )

+                {

+                    request.addShellEnvironment( variable.getKey(), variable.getValue() );

+                }

+            }

+

+            for ( int invocationIndex = 1;; invocationIndex++ )

+            {

+                if ( invocationIndex > 1 && !invokerProperties.isInvocationDefined( invocationIndex ) )

+                {

+                    break;

+                }

+

+                request.setBaseDirectory( basedir );

+

+                request.setPomFile( pomFile );

+

+                request.setGoals( goals );

+

+                request.setProfiles( profiles );

+

+                request.setMavenOpts( mavenOpts );

+

+                request.setOffline( false );

+

+                request.setUserSettingsFile( settingsFile );

+

+                Properties systemProperties =

+                    getSystemProperties( basedir, invokerProperties.getSystemPropertiesFile( invocationIndex ) );

+                request.setProperties( systemProperties );

+

+                invokerProperties.configureInvocation( request, invocationIndex );

+

+                if ( getLog().isDebugEnabled() )

+                {

+                    try

+                    {

+                        getLog().debug( "Using MAVEN_OPTS: " + request.getMavenOpts() );

+                        getLog().debug( "Executing: " + new MavenCommandLineBuilder().build( request ) );

+                    }

+                    catch ( CommandLineConfigurationException e )

+                    {

+                        getLog().debug( "Failed to display command line: " + e.getMessage() );

+                    }

+                }

+

+                InvocationResult result;

+

+                try

+                {

+                    result = invoker.execute( request );

+                }

+                catch ( final MavenInvocationException e )

+                {

+                    getLog().debug( "Error invoking Maven: " + e.getMessage(), e );

+                    throw new RunFailureException( "Maven invocation failed. " + e.getMessage(),

+                                                   BuildJob.Result.FAILURE_BUILD );

+                }

+

+                verify( result, invocationIndex, invokerProperties, logger );

+            }

+

+            scriptRunner.run( "post-build script", basedir, postBuildHookScript, context, logger,

+                              BuildJob.Result.FAILURE_POST_HOOK, true );

+        }

+        catch ( IOException e )

+        {

+            throw new MojoExecutionException( e.getMessage(), e );

+        }

+        finally

+        {

+            if ( logger != null )

+            {

+                logger.close();

+            }

+        }

+        return true;

+    }

+

+    private void setupLoggerForBuildJob( FileLogger logger, final InvocationRequest request )

+    {

+        if ( logger != null )

+        {

+            request.setErrorHandler( logger );

+

+            request.setOutputHandler( logger );

+        }

+    }

+

+    /**

+     * Initializes the build logger for the specified project. This will write the logging information into

+     * {@code build.log}.

+     *

+     * @param basedir The base directory of the project, must not be <code>null</code>.

+     * @return The build logger or <code>null</code> if logging has been disabled.

+     * @throws org.apache.maven.plugin.MojoExecutionException If the log file could not be created.

+     */

+    private FileLogger setupBuildLogFile( File basedir )

+        throws MojoExecutionException

+    {

+        FileLogger logger = null;

+

+        if ( !noLog )

+        {

+            File outputLog = new File( basedir, "build.log" );

+            try

+            {

+                if ( streamLogs )

+                {

+                    logger = new FileLogger( outputLog, getLog() );

+                }

+                else

+                {

+                    logger = new FileLogger( outputLog );

+                }

+

+                getLog().debug( "Build log initialized in: " + outputLog );

+            }

+            catch ( IOException e )

+            {

+                throw new MojoExecutionException( "Error initializing build logfile in: " + outputLog, e );

+            }

+        }

+

+        return logger;

+    }

+

+    /**

+     * Gets the system properties to use for the specified project.

+     *

+     * @param basedir The base directory of the project, must not be <code>null</code>.

+     * @param filename The filename to the properties file to load, may be <code>null</code> to use the default path

+     *            given by {@link #testPropertiesFile}.

+     * @return The system properties to use, may be empty but never <code>null</code>.

+     * @throws org.apache.maven.plugin.MojoExecutionException If the properties file exists but could not be read.

+     */

+    private Properties getSystemProperties( final File basedir, final String filename )

+        throws MojoExecutionException

+    {

+        Properties collectedTestProperties = new Properties();

+

+        if ( properties != null )

+        {

+            // MINVOKER-118: property can have empty value, which is not accepted by collectedTestProperties

+            for ( Map.Entry<String, String> entry : properties.entrySet() )

+            {

+                if ( entry.getValue() != null )

+                {

+                    collectedTestProperties.put( entry.getKey(), entry.getValue() );

+                }

+            }

+        }

+

+        File propertiesFile = null;

+        if ( filename != null )

+        {

+            propertiesFile = new File( basedir, filename );

+        }

+        else if ( testPropertiesFile != null )

+        {

+            propertiesFile = new File( basedir, testPropertiesFile );

+        }

+

+        if ( propertiesFile != null && propertiesFile.isFile() )

+        {

+            InputStream fin = null;

+            try

+            {

+                fin = new FileInputStream( propertiesFile );

+

+                Properties loadedProperties = new Properties();

+                loadedProperties.load( fin );

+                fin.close();

+                fin = null;

+                collectedTestProperties.putAll( loadedProperties );

+            }

+            catch ( IOException e )

+            {

+                throw new MojoExecutionException( "Error reading system properties from " + propertiesFile );

+            }

+            finally

+            {

+                IOUtil.close( fin );

+            }

+        }

+

+        return collectedTestProperties;

+    }

+

+    /**

+     * Verifies the invocation result.

+     *

+     * @param result The invocation result to check, must not be <code>null</code>.

+     * @param invocationIndex The index of the invocation for which to check the exit code, must not be negative.

+     * @param invokerProperties The invoker properties used to check the exit code, must not be <code>null</code>.

+     * @param logger The build logger, may be <code>null</code> if logging is disabled.

+     * @throws org.apache.maven.shared.scriptinterpreter.RunFailureException If the invocation result indicates a build

+     *             failure.

+     */

+    private void verify( InvocationResult result, int invocationIndex, InvokerProperties invokerProperties,

+                         FileLogger logger )

+        throws RunFailureException

+    {

+        if ( result.getExecutionException() != null )

+        {

+            throw new RunFailureException( "The Maven invocation failed. "

+                + result.getExecutionException().getMessage(), BuildJob.Result.ERROR );

+        }

+        else if ( !invokerProperties.isExpectedResult( result.getExitCode(), invocationIndex ) )

+        {

+            StringBuilder buffer = new StringBuilder( 256 );

+            buffer.append( "The build exited with code " ).append( result.getExitCode() ).append( ". " );

+            if ( logger != null )

+            {

+                buffer.append( "See " );

+                buffer.append( logger.getOutputFile().getAbsolutePath() );

+                buffer.append( " for details." );

+            }

+            else

+            {

+                buffer.append( "See console output for details." );

+            }

+            throw new RunFailureException( buffer.toString(), BuildJob.Result.FAILURE_BUILD );

+        }

+    }

+

+    /**

+     * Gets the goal list for the specified project.

+     *

+     * @param basedir The base directory of the project, must not be <code>null</code>.

+     * @return The list of goals to run when building the project, may be empty but never <code>null</code>.

+     * @throws org.apache.maven.plugin.MojoExecutionException If the profile file could not be read.

+     */

+    List<String> getGoals( final File basedir )

+        throws MojoExecutionException

+    {

+        try

+        {

+            // FIXME: Currently we have null for goalsFile which has been removed.

+            // This might mean we can remove getGoals() at all ? Check this.

+            return getTokens( basedir, null, goals );

+        }

+        catch ( IOException e )

+        {

+            throw new MojoExecutionException( "error reading goals", e );

+        }

+    }

+

+    /**

+     * Gets the profile list for the specified project.

+     *

+     * @param basedir The base directory of the project, must not be <code>null</code>.

+     * @return The list of profiles to activate when building the project, may be empty but never <code>null</code>.

+     * @throws org.apache.maven.plugin.MojoExecutionException If the profile file could not be read.

+     */

+    List<String> getProfiles( File basedir )

+        throws MojoExecutionException

+    {

+        try

+        {

+            return getTokens( basedir, null, profiles );

+        }

+        catch ( IOException e )

+        {

+            throw new MojoExecutionException( "error reading profiles", e );

+        }

+    }

+

+    private List<String> calculateExcludes()

+        throws IOException

+    {

+        List<String> excludes =

+            ( pomExcludes != null ) ? new ArrayList<String>( pomExcludes ) : new ArrayList<String>();

+        if ( this.settingsFile != null )

+        {

+            String exclude = relativizePath( this.settingsFile, projectsDirectory.getCanonicalPath() );

+            if ( exclude != null )

+            {

+                excludes.add( exclude.replace( '\\', '/' ) );

+                getLog().debug( "Automatically excluded " + exclude + " from project scanning" );

+            }

+        }

+        return excludes;

+

+    }

+

+    /**

+     * @return The list of setupUp jobs.

+     * @throws IOException

+     * @see {@link #setupIncludes}

+     */

+    private BuildJob[] getSetupBuildJobsFromFolders()

+        throws IOException

+    {

+        List<String> excludes = calculateExcludes();

+

+        BuildJob[] setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP );

+        if ( getLog().isDebugEnabled() )

+        {

+            getLog().debug( "Setup projects: " + Arrays.asList( setupPoms ) );

+        }

+

+        return setupPoms;

+    }

+

+    /**

+     * Gets the build jobs that should be processed. Note that the order of the returned build jobs is significant.

+     *

+     * @return The build jobs to process, may be empty but never <code>null</code>.

+     * @throws java.io.IOException If the projects directory could not be scanned.

+     */

+    BuildJob[] getBuildJobs()

+        throws IOException

+    {

+        BuildJob[] buildJobs;

+

+        if ( invokerTest == null )

+        {

+            List<String> excludes = calculateExcludes();

+

+            BuildJob[] setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP );

+            if ( getLog().isDebugEnabled() )

+            {

+                getLog().debug( "Setup projects: " + Arrays.asList( setupPoms ) );

+            }

+

+            BuildJob[] normalPoms = scanProjectsDirectory( pomIncludes, excludes, BuildJob.Type.NORMAL );

+

+            Map<String, BuildJob> uniquePoms = new LinkedHashMap<String, BuildJob>();

+            for ( BuildJob setupPom : setupPoms )

+            {

+                uniquePoms.put( setupPom.getProject(), setupPom );

+            }

+            for ( BuildJob normalPom : normalPoms )

+            {

+                if ( !uniquePoms.containsKey( normalPom.getProject() ) )

+                {

+                    uniquePoms.put( normalPom.getProject(), normalPom );

+                }

+            }

+

+            buildJobs = uniquePoms.values().toArray( new BuildJob[uniquePoms.size()] );

+        }

+        else

+        {

+            String[] testRegexes = StringUtils.split( invokerTest, "," );

+            List<String> includes = new ArrayList<String>( testRegexes.length );

+            List<String> excludes = new ArrayList<String>();

+

+            for ( String regex : testRegexes )

+            {

+                // user just use -Dinvoker.test=MWAR191,MNG111 to use a directory thats the end is not pom.xml

+                if ( regex.startsWith( "!" ) )

+                {

+                    excludes.add( regex.substring( 1 ) );

+                }

+                else

+                {

+                    includes.add( regex );

+                }

+            }

+

+            // it would be nice if we could figure out what types these are... but perhaps

+            // not necessary for the -Dinvoker.test=xxx t

+            buildJobs = scanProjectsDirectory( includes, excludes, BuildJob.Type.DIRECT );

+        }

+

+        relativizeProjectPaths( buildJobs );

+

+        return buildJobs;

+    }

+

+    /**

+     * Scans the projects directory for projects to build. Both (POM) files and mere directories will be matched by the

+     * scanner patterns. If the patterns match a directory which contains a file named "pom.xml", the results will

+     * include the path to this file rather than the directory path in order to avoid duplicate invocations of the same

+     * project.

+     *

+     * @param includes The include patterns for the scanner, may be <code>null</code>.

+     * @param excludes The exclude patterns for the scanner, may be <code>null</code> to exclude nothing.

+     * @param type The type to assign to the resulting build jobs, must not be <code>null</code>.

+     * @return The build jobs matching the patterns, never <code>null</code>.

+     * @throws java.io.IOException If the project directory could not be scanned.

+     */

+    private BuildJob[] scanProjectsDirectory( List<String> includes, List<String> excludes, String type )

+        throws IOException

+    {

+        if ( !projectsDirectory.isDirectory() )

+        {

+            return new BuildJob[0];

+        }

+

+        DirectoryScanner scanner = new DirectoryScanner();

+        scanner.setBasedir( projectsDirectory.getCanonicalFile() );

+        scanner.setFollowSymlinks( false );

+        if ( includes != null )

+        {

+            scanner.setIncludes( includes.toArray( new String[includes.size()] ) );

+        }

+        if ( excludes != null )

+        {

+            scanner.setExcludes( excludes.toArray( new String[excludes.size()] ) );

+        }

+        scanner.addDefaultExcludes();

+        scanner.scan();

+

+        Map<String, BuildJob> matches = new LinkedHashMap<String, BuildJob>();

+

+        for ( String includedFile : scanner.getIncludedFiles() )

+        {

+            matches.put( includedFile, new BuildJob( includedFile, type ) );

+        }

+

+        for ( String includedDir : scanner.getIncludedDirectories() )

+        {

+            String includedFile = includedDir + File.separatorChar + "pom.xml";

+            if ( new File( scanner.getBasedir(), includedFile ).isFile() )

+            {

+                matches.put( includedFile, new BuildJob( includedFile, type ) );

+            }

+            else

+            {

+                matches.put( includedDir, new BuildJob( includedDir, type ) );

+            }

+        }

+

+        return matches.values().toArray( new BuildJob[matches.size()] );

+    }

+

+    /**

+     * Relativizes the project paths of the specified build jobs against the directory specified by

+     * {@link #projectsDirectory} (if possible). If a project path does not denote a sub path of the projects directory,

+     * it is returned as is.

+     *

+     * @param buildJobs The build jobs whose project paths should be relativized, must not be <code>null</code> nor

+     *            contain <code>null</code> elements.

+     * @throws java.io.IOException If any path could not be relativized.

+     */

+    private void relativizeProjectPaths( BuildJob[] buildJobs )

+        throws IOException

+    {

+        String projectsDirPath = projectsDirectory.getCanonicalPath();

+

+        for ( BuildJob buildJob : buildJobs )

+        {

+            String projectPath = buildJob.getProject();

+

+            File file = new File( projectPath );

+

+            if ( !file.isAbsolute() )

+            {

+                file = new File( projectsDirectory, projectPath );

+            }

+

+            String relativizedPath = relativizePath( file, projectsDirPath );

+

+            if ( relativizedPath == null )

+            {

+                relativizedPath = projectPath;

+            }

+

+            buildJob.setProject( relativizedPath );

+        }

+    }

+

+    /**

+     * Relativizes the specified path against the given base directory. Besides relativization, the returned path will

+     * also be normalized, e.g. directory references like ".." will be removed.

+     *

+     * @param path The path to relativize, must not be <code>null</code>.

+     * @param basedir The (canonical path of the) base directory to relativize against, must not be <code>null</code>.

+     * @return The relative path in normal form or <code>null</code> if the input path does not denote a sub path of the

+     *         base directory.

+     * @throws java.io.IOException If the path could not be relativized.

+     */

+    private String relativizePath( File path, String basedir )

+        throws IOException

+    {

+        String relativizedPath = path.getCanonicalPath();

+

+        if ( relativizedPath.startsWith( basedir ) )

+        {

+            relativizedPath = relativizedPath.substring( basedir.length() );

+            if ( relativizedPath.startsWith( File.separator ) )

+            {

+                relativizedPath = relativizedPath.substring( File.separator.length() );

+            }

+

+            return relativizedPath;

+        }

+        else

+        {

+            return null;

+        }

+    }

+

+    /**

+     * Returns the map-based value source used to interpolate POMs and other stuff.

+     *

+     * @param escapeXml {@code true}, to escape any XML special characters in the property values; {@code false}, to not

+     * escape any property values.

+     *

+     * @return The map-based value source for interpolation, never <code>null</code>.

+     */

+    private Map<String, Object> getInterpolationValueSource( final boolean escapeXml )

+    {

+        Map<String, Object> props = new HashMap<String, Object>();

+

+        if ( filterProperties != null )

+        {

+            props.putAll( filterProperties );

+        }

+        props.put( "basedir", this.project.getBasedir().getAbsolutePath() );

+        props.put( "baseurl", toUrl( this.project.getBasedir().getAbsolutePath() ) );

+        if ( settings.getLocalRepository() != null )

+        {

+            props.put( "localRepository", settings.getLocalRepository() );

+            props.put( "localRepositoryUrl", toUrl( settings.getLocalRepository() ) );

+        }

+

+        return new CompositeMap( this.project, props, escapeXml );

+    }

+

+    /**

+     * Converts the specified filesystem path to a URL. The resulting URL has no trailing slash regardless whether the

+     * path denotes a file or a directory.

+     *

+     * @param filename The filesystem path to convert, must not be <code>null</code>.

+     * @return The <code>file:</code> URL for the specified path, never <code>null</code>.

+     */

+    private static String toUrl( String filename )

+    {

+        /*

+         * NOTE: Maven fails to properly handle percent-encoded "file:" URLs (WAGON-111) so don't use File.toURI() here

+         * as-is but use the decoded path component in the URL.

+         */

+        String url = "file://" + new File( filename ).toURI().getPath();

+        if ( url.endsWith( "/" ) )

+        {

+            url = url.substring( 0, url.length() - 1 );

+        }

+        return url;

+    }

+

+    /**

+     * Gets goal/profile names for the specified project, either directly from the plugin configuration or from an

+     * external token file.

+     *

+     * @param basedir The base directory of the test project, must not be <code>null</code>.

+     * @param filename The (simple) name of an optional file in the project base directory from which to read

+     *            goals/profiles, may be <code>null</code>.

+     * @param defaultTokens The list of tokens to return in case the specified token file does not exist, may be

+     *            <code>null</code>.

+     * @return The list of goal/profile names, may be empty but never <code>null</code>.

+     * @throws java.io.IOException If the token file exists but could not be parsed.

+     */

+    private List<String> getTokens( File basedir, String filename, List<String> defaultTokens )

+        throws IOException

+    {

+        List<String> tokens = ( defaultTokens != null ) ? defaultTokens : new ArrayList<String>();

+

+        if ( StringUtils.isNotEmpty( filename ) )

+        {

+            File tokenFile = new File( basedir, filename );

+

+            if ( tokenFile.exists() )

+            {

+                tokens = readTokens( tokenFile );

+            }

+        }

+

+        return tokens;

+    }

+

+    /**

+     * Reads the tokens from the specified file. Tokens are separated either by line terminators or commas. During

+     * parsing, the file contents will be interpolated.

+     *

+     * @param tokenFile The file to read the tokens from, must not be <code>null</code>.

+     * @return The list of tokens, may be empty but never <code>null</code>.

+     * @throws java.io.IOException If the token file could not be read.

+     */

+    private List<String> readTokens( final File tokenFile )

+        throws IOException

+    {

+        List<String> result = new ArrayList<String>();

+

+        BufferedReader reader = null;

+        try

+        {

+            Map<String, Object> composite = getInterpolationValueSource( false );

+            reader = new BufferedReader( new InterpolationFilterReader( newReader( tokenFile ), composite ) );

+

+            for ( String line = reader.readLine(); line != null; line = reader.readLine() )

+            {

+                result.addAll( collectListFromCSV( line ) );

+            }

+

+            reader.close();

+            reader = null;

+        }

+        finally

+        {

+            IOUtil.close( reader );

+        }

+

+        return result;

+    }

+

+    /**

+     * Gets a list of comma separated tokens from the specified line.

+     *

+     * @param csv The line with comma separated tokens, may be <code>null</code>.

+     * @return The list of tokens from the line, may be empty but never <code>null</code>.

+     */

+    private List<String> collectListFromCSV( final String csv )

+    {

+        final List<String> result = new ArrayList<String>();

+

+        if ( ( csv != null ) && ( csv.trim().length() > 0 ) )

+        {

+            final StringTokenizer st = new StringTokenizer( csv, "," );

+

+            while ( st.hasMoreTokens() )

+            {

+                result.add( st.nextToken().trim() );

+            }

+        }

+

+        return result;

+    }

+

+    /**

+     * Interpolates the specified POM/settings file to a temporary file. The destination file may be same as the input

+     * file, i.e. interpolation can be performed in-place.

+     * <p>

+     * <b>Note:</b>This methods expects the file to be a XML file and applies special XML escaping during interpolation.

+     * </p>

+     *

+     * @param originalFile The XML file to interpolate, must not be <code>null</code>.

+     * @param interpolatedFile The target file to write the interpolated contents of the original file to, must not be

+     * <code>null</code>.

+     *

+     * @throws org.apache.maven.plugin.MojoExecutionException If the target file could not be created.

+     */

+    void buildInterpolatedFile( File originalFile, File interpolatedFile )

+        throws MojoExecutionException

+    {

+        getLog().debug( "Interpolate " + originalFile.getPath() + " to " + interpolatedFile.getPath() );

+

+        try

+        {

+            String xml;

+

+            Reader reader = null;

+            try

+            {

+                // interpolation with token @...@

+                Map<String, Object> composite = getInterpolationValueSource( true );

+                reader =

+                    new InterpolationFilterReader( ReaderFactory.newXmlReader( originalFile ), composite, "@", "@" );

+

+                xml = IOUtil.toString( reader );

+

+                reader.close();

+                reader = null;

+            }

+            finally

+            {

+                IOUtil.close( reader );

+            }

+

+            Writer writer = null;

+            try

+            {

+                interpolatedFile.getParentFile().mkdirs();

+                writer = WriterFactory.newXmlWriter( interpolatedFile );

+                writer.write( xml );

+                writer.close();

+                writer = null;

+            }

+            finally

+            {

+                IOUtil.close( writer );

+            }

+        }

+        catch ( IOException e )

+        {

+            throw new MojoExecutionException( "Failed to interpolate file " + originalFile.getPath(), e );

+        }

+    }

+

+    /**

+     * Gets the (interpolated) invoker properties for an integration test.

+     *

+     * @param projectDirectory The base directory of the IT project, must not be <code>null</code>.

+     * @return The invoker properties, may be empty but never <code>null</code>.

+     * @throws org.apache.maven.plugin.MojoExecutionException If an I/O error occurred during reading the properties.

+     */

+    private InvokerProperties getInvokerProperties( final File projectDirectory )

+        throws MojoExecutionException

+    {

+        Properties props = new Properties();

+        if ( invokerPropertiesFile != null )

+        {

+            File propertiesFile = new File( projectDirectory, invokerPropertiesFile );

+            if ( propertiesFile.isFile() )

+            {

+                InputStream in = null;

+                try

+                {

+                    in = new FileInputStream( propertiesFile );

+                    props.load( in );

+                    in.close();

+                    in = null;

+                }

+                catch ( IOException e )

+                {

+                    throw new MojoExecutionException( "Failed to read invoker properties: " + propertiesFile, e );

+                }

+                finally

+                {

+                    IOUtil.close( in );

+                }

+            }

+

+            Interpolator interpolator = new RegexBasedInterpolator();

+            interpolator.addValueSource( new MapBasedValueSource( getInterpolationValueSource( false ) ) );

+            // CHECKSTYLE_OFF: LineLength

+            for ( String key : props.stringPropertyNames() )

+            {

+                String value = props.getProperty( key );

+                try

+                {

+                    value = interpolator.interpolate( value, "" );

+                }

+                catch ( InterpolationException e )

+                {

+                    throw new MojoExecutionException( "Failed to interpolate invoker properties: " + propertiesFile,

+                                                      e );

+                }

+                props.setProperty( key, value );

+            }

+            // CHECKSTYLE_ON: LineLength

+        }

+        return new InvokerProperties( props );

+    }

+

+    protected boolean isParallelRun()

+    {

+        return parallelThreads > 1;

+    }

+

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/CompositeMap.java b/src/main/java/org/apache/maven/plugins/invoker/CompositeMap.java
similarity index 98%
rename from src/main/java/org/apache/maven/plugin/invoker/CompositeMap.java
rename to src/main/java/org/apache/maven/plugins/invoker/CompositeMap.java
index db26ae3..bd1fe37 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/CompositeMap.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/CompositeMap.java
@@ -1,259 +1,259 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
-
-/**
- * A map-like source to interpolate expressions.
- *
- * @author Olivier Lamy
- * @since 1.1
- * @version $Id$
- */
-class CompositeMap
-    implements Map<String, Object>
-{
-
-    /**
-     * The Maven project from which to extract interpolated values, never <code>null</code>.
-     */
-    private MavenProject mavenProject;
-
-    /**
-     * The set of additional properties from which to extract interpolated values, never <code>null</code>.
-     */
-    private Map<String, Object> properties;
-
-    /**
-     * Flag indicating to escape XML special characters.
-     */
-    private final boolean escapeXml;
-
-    /**
-     * Creates a new interpolation source backed by the specified Maven project and some user-specified properties.
-     *
-     * @param mavenProject The Maven project from which to extract interpolated values, must not be <code>null</code>.
-     * @param properties The set of additional properties from which to extract interpolated values, may be
-     *            <code>null</code>.
-     * @param escapeXml {@code true}, to escape any XML special characters; {@code false}, to not perform any escaping.
-     */
-    protected CompositeMap( MavenProject mavenProject, Map<String, Object> properties, boolean escapeXml )
-    {
-        if ( mavenProject == null )
-        {
-            throw new IllegalArgumentException( "no project specified" );
-        }
-        this.mavenProject = mavenProject;
-        this.properties = properties == null ? new HashMap<String, Object>() : properties;
-        this.escapeXml = escapeXml;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#clear()
-     */
-    public void clear()
-    {
-        // nothing here
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#containsKey(java.lang.Object)
-     */
-    public boolean containsKey( Object key )
-    {
-        if ( !( key instanceof String ) )
-        {
-            return false;
-        }
-
-        String expression = (String) key;
-        if ( expression.startsWith( "project." ) || expression.startsWith( "pom." ) )
-        {
-            try
-            {
-                Object evaluated = ReflectionValueExtractor.evaluate( expression, this.mavenProject );
-                if ( evaluated != null )
-                {
-                    return true;
-                }
-            }
-            catch ( Exception e )
-            {
-                // uhm do we have to throw a RuntimeException here ?
-            }
-        }
-
-        return properties.containsKey( key ) || mavenProject.getProperties().containsKey( key );
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#containsValue(java.lang.Object)
-     */
-    public boolean containsValue( Object value )
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#entrySet()
-     */
-    public Set<Entry<String, Object>> entrySet()
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#get(java.lang.Object)
-     */
-    public Object get( Object key )
-    {
-        if ( !( key instanceof String ) )
-        {
-            return null;
-        }
-
-        Object value = null;
-        String expression = (String) key;
-        if ( expression.startsWith( "project." ) || expression.startsWith( "pom." ) )
-        {
-            try
-            {
-                Object evaluated = ReflectionValueExtractor.evaluate( expression, this.mavenProject );
-                if ( evaluated != null )
-                {
-                    value = evaluated;
-                }
-            }
-            catch ( Exception e )
-            {
-                // uhm do we have to throw a RuntimeException here ?
-            }
-        }
-
-        if ( value == null )
-        {
-            value = properties.get( key );
-        }
-
-        if ( value == null )
-        {
-            value = this.mavenProject.getProperties().get( key );
-        }
-
-        if ( value != null && this.escapeXml )
-        {
-            value = value.toString().
-                replaceAll( "\"", "&quot;" ).
-                replaceAll( "<", "&lt;" ).
-                replaceAll( ">", "&gt;" ).
-                replaceAll( "&", "&amp;" );
-
-        }
-
-        return value;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#isEmpty()
-     */
-    public boolean isEmpty()
-    {
-        return this.mavenProject.getProperties().isEmpty() && this.properties.isEmpty();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#keySet()
-     */
-    public Set<String> keySet()
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#put(java.lang.Object, java.lang.Object)
-     */
-    public Object put( String key, Object value )
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#putAll(java.util.Map)
-     */
-    public void putAll( Map<? extends String, ? extends Object> t )
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#remove(java.lang.Object)
-     */
-    public Object remove( Object key )
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#size()
-     */
-    public int size()
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @see java.util.Map#values()
-     */
-    public Collection<Object> values()
-    {
-        throw new UnsupportedOperationException();
-    }
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.util.Collection;

+import java.util.HashMap;

+import java.util.Map;

+import java.util.Set;

+

+import org.apache.maven.project.MavenProject;

+import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;

+

+/**

+ * A map-like source to interpolate expressions.

+ *

+ * @author Olivier Lamy

+ * @since 1.1

+ * @version $Id: CompositeMap.java 1784076 2017-02-23 00:35:39Z schulte $

+ */

+class CompositeMap

+    implements Map<String, Object>

+{

+

+    /**

+     * The Maven project from which to extract interpolated values, never <code>null</code>.

+     */

+    private MavenProject mavenProject;

+

+    /**

+     * The set of additional properties from which to extract interpolated values, never <code>null</code>.

+     */

+    private Map<String, Object> properties;

+

+    /**

+     * Flag indicating to escape XML special characters.

+     */

+    private final boolean escapeXml;

+

+    /**

+     * Creates a new interpolation source backed by the specified Maven project and some user-specified properties.

+     *

+     * @param mavenProject The Maven project from which to extract interpolated values, must not be <code>null</code>.

+     * @param properties The set of additional properties from which to extract interpolated values, may be

+     *            <code>null</code>.

+     * @param escapeXml {@code true}, to escape any XML special characters; {@code false}, to not perform any escaping.

+     */

+    protected CompositeMap( MavenProject mavenProject, Map<String, Object> properties, boolean escapeXml )

+    {

+        if ( mavenProject == null )

+        {

+            throw new IllegalArgumentException( "no project specified" );

+        }

+        this.mavenProject = mavenProject;

+        this.properties = properties == null ? new HashMap<String, Object>() : properties;

+        this.escapeXml = escapeXml;

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#clear()

+     */

+    public void clear()

+    {

+        // nothing here

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#containsKey(java.lang.Object)

+     */

+    public boolean containsKey( Object key )

+    {

+        if ( !( key instanceof String ) )

+        {

+            return false;

+        }

+

+        String expression = (String) key;

+        if ( expression.startsWith( "project." ) || expression.startsWith( "pom." ) )

+        {

+            try

+            {

+                Object evaluated = ReflectionValueExtractor.evaluate( expression, this.mavenProject );

+                if ( evaluated != null )

+                {

+                    return true;

+                }

+            }

+            catch ( Exception e )

+            {

+                // uhm do we have to throw a RuntimeException here ?

+            }

+        }

+

+        return properties.containsKey( key ) || mavenProject.getProperties().containsKey( key );

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#containsValue(java.lang.Object)

+     */

+    public boolean containsValue( Object value )

+    {

+        throw new UnsupportedOperationException();

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#entrySet()

+     */

+    public Set<Entry<String, Object>> entrySet()

+    {

+        throw new UnsupportedOperationException();

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#get(java.lang.Object)

+     */

+    public Object get( Object key )

+    {

+        if ( !( key instanceof String ) )

+        {

+            return null;

+        }

+

+        Object value = null;

+        String expression = (String) key;

+        if ( expression.startsWith( "project." ) || expression.startsWith( "pom." ) )

+        {

+            try

+            {

+                Object evaluated = ReflectionValueExtractor.evaluate( expression, this.mavenProject );

+                if ( evaluated != null )

+                {

+                    value = evaluated;

+                }

+            }

+            catch ( Exception e )

+            {

+                // uhm do we have to throw a RuntimeException here ?

+            }

+        }

+

+        if ( value == null )

+        {

+            value = properties.get( key );

+        }

+

+        if ( value == null )

+        {

+            value = this.mavenProject.getProperties().get( key );

+        }

+

+        if ( value != null && this.escapeXml )

+        {

+            value = value.toString().

+                replaceAll( "\"", "&quot;" ).

+                replaceAll( "<", "&lt;" ).

+                replaceAll( ">", "&gt;" ).

+                replaceAll( "&", "&amp;" );

+

+        }

+

+        return value;

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#isEmpty()

+     */

+    public boolean isEmpty()

+    {

+        return this.mavenProject.getProperties().isEmpty() && this.properties.isEmpty();

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#keySet()

+     */

+    public Set<String> keySet()

+    {

+        throw new UnsupportedOperationException();

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#put(java.lang.Object, java.lang.Object)

+     */

+    public Object put( String key, Object value )

+    {

+        throw new UnsupportedOperationException();

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#putAll(java.util.Map)

+     */

+    public void putAll( Map<? extends String, ? extends Object> t )

+    {

+        throw new UnsupportedOperationException();

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#remove(java.lang.Object)

+     */

+    public Object remove( Object key )

+    {

+        throw new UnsupportedOperationException();

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#size()

+     */

+    public int size()

+    {

+        throw new UnsupportedOperationException();

+    }

+

+    /**

+     * {@inheritDoc}

+     *

+     * @see java.util.Map#values()

+     */

+    public Collection<Object> values()

+    {

+        throw new UnsupportedOperationException();

+    }

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/FileLogger.java b/src/main/java/org/apache/maven/plugins/invoker/FileLogger.java
similarity index 94%
rename from src/main/java/org/apache/maven/plugin/invoker/FileLogger.java
rename to src/main/java/org/apache/maven/plugins/invoker/FileLogger.java
index d8eae3f..1073606 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/FileLogger.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/FileLogger.java
@@ -1,62 +1,62 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.IOException;
-
-import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.shared.invoker.InvocationOutputHandler;
-import org.apache.maven.shared.scriptinterpreter.ExecutionLogger;
-
-/**
- * @version $Id$
- */
-class FileLogger
-    extends org.apache.maven.shared.scriptinterpreter.FileLogger
-    implements InvocationOutputHandler, ExecutionLogger
-{
-
-    /**
-     * Creates a new logger that writes to the specified file.
-     *
-     * @param outputFile The path to the output file, must not be <code>null</code>.
-     * @throws IOException If the output file could not be created.
-     */
-    public FileLogger( File outputFile )
-        throws IOException
-    {
-        super( outputFile, null );
-    }
-
-    /**
-     * Creates a new logger that writes to the specified file and optionally mirrors messages to the given mojo logger.
-     *
-     * @param outputFile The path to the output file, must not be <code>null</code>.
-     * @param log The mojo logger to additionally output messages to, may be <code>null</code> if not used.
-     * @throws IOException If the output file could not be created.
-     */
-    public FileLogger( File outputFile, Log log )
-        throws IOException
-    {
-        super( outputFile, log );
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.IOException;

+

+import org.apache.maven.plugin.logging.Log;

+import org.apache.maven.shared.invoker.InvocationOutputHandler;

+import org.apache.maven.shared.scriptinterpreter.ExecutionLogger;

+

+/**

+ * @version $Id: FileLogger.java 1671476 2015-04-06 03:53:29Z dantran $

+ */

+class FileLogger

+    extends org.apache.maven.shared.scriptinterpreter.FileLogger

+    implements InvocationOutputHandler, ExecutionLogger

+{

+

+    /**

+     * Creates a new logger that writes to the specified file.

+     *

+     * @param outputFile The path to the output file, must not be <code>null</code>.

+     * @throws IOException If the output file could not be created.

+     */

+    public FileLogger( File outputFile )

+        throws IOException

+    {

+        super( outputFile, null );

+    }

+

+    /**

+     * Creates a new logger that writes to the specified file and optionally mirrors messages to the given mojo logger.

+     *

+     * @param outputFile The path to the output file, must not be <code>null</code>.

+     * @param log The mojo logger to additionally output messages to, may be <code>null</code> if not used.

+     * @throws IOException If the output file could not be created.

+     */

+    public FileLogger( File outputFile, Log log )

+        throws IOException

+    {

+        super( outputFile, log );

+    }

+

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/InstallMojo.java b/src/main/java/org/apache/maven/plugins/invoker/InstallMojo.java
similarity index 99%
rename from src/main/java/org/apache/maven/plugin/invoker/InstallMojo.java
rename to src/main/java/org/apache/maven/plugins/invoker/InstallMojo.java
index ee23e87..b0a0c21 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/InstallMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InstallMojo.java
@@ -1,605 +1,605 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.IOException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.Map;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.factory.ArtifactFactory;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Parent;
-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.plugins.annotations.ResolutionScope;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.project.ProjectBuildingRequest;
-import org.apache.maven.shared.artifact.install.ArtifactInstaller;
-import org.apache.maven.shared.dependencies.DefaultDependableCoordinate;
-import org.apache.maven.shared.dependencies.resolve.DependencyResolver;
-import org.apache.maven.shared.dependencies.resolve.DependencyResolverException;
-import org.apache.maven.shared.repository.RepositoryManager;
-import org.codehaus.plexus.util.FileUtils;
-
-/**
- * Installs the project artifacts of the main build into the local repository as a preparation to run the sub projects.
- * More precisely, all artifacts of the project itself, all its locally reachable parent POMs and all its dependencies
- * from the reactor will be installed to the local repository.
- *
- * @since 1.2
- * @author Paul Gier
- * @author Benjamin Bentmann
- * @version $Id$
- */
-// CHECKSTYLE_OFF: LineLength
-@Mojo( name = "install", defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true )
-// CHECKSTYLE_ON: LineLength
-public class InstallMojo
-    extends AbstractMojo
-{
-
-    /**
-     * Maven artifact install component to copy artifacts to the local repository.
-     */
-    @Component
-    private ArtifactInstaller installer;
-    
-    @Component
-    private RepositoryManager repositoryManager;
-
-    /**
-     * The component used to create artifacts.
-     */
-    @Component
-    private ArtifactFactory artifactFactory;
-
-    /**
-     */
-    @Parameter( property = "localRepository", required = true, readonly = true )
-    private ArtifactRepository localRepository;
-
-    /**
-     * The path to the local repository into which the project artifacts should be installed for the integration tests.
-     * If not set, the regular local repository will be used. To prevent soiling of your regular local repository with
-     * possibly broken artifacts, it is strongly recommended to use an isolated repository for the integration tests
-     * (e.g. <code>${project.build.directory}/it-repo</code>).
-     */
-    @Parameter( property = "invoker.localRepositoryPath", 
-                defaultValue = "${session.localRepository.basedir}", required = true )
-    private File localRepositoryPath;
-
-    /**
-     * The current Maven project.
-     */
-    @Parameter( defaultValue = "${project}", readonly = true, required = true )
-    private MavenProject project;
-
-    @Parameter( defaultValue = "${session}", readonly = true, required = true )
-    private MavenSession session;
-    
-    /**
-     * The set of Maven projects in the reactor build.
-     */
-    @Parameter( defaultValue = "${reactorProjects}", readonly = true )
-    private Collection<MavenProject> reactorProjects;
-
-    /**
-     * A flag used to disable the installation procedure. This is primarily intended for usage from the command line to
-     * occasionally adjust the build.
-     *
-     * @since 1.4
-     */
-    @Parameter( property = "invoker.skip", defaultValue = "false" )
-    private boolean skipInstallation;
-
-    /**
-     * The identifiers of already installed artifacts, used to avoid multiple installation of the same artifact.
-     */
-    private Collection<String> installedArtifacts;
-
-    /**
-     * The identifiers of already copied artifacts, used to avoid multiple installation of the same artifact.
-     */
-    private Collection<String> copiedArtifacts;
-
-    /**
-     * Extra dependencies that need to be installed on the local repository.<BR>
-     * Format:
-     *
-     * <pre>
-     * groupId:artifactId:version:type:classifier
-     * </pre>
-     *
-     * Examples:
-     *
-     * <pre>
-     * org.apache.maven.plugins:maven-clean-plugin:2.4:maven-plugin
-     * org.apache.maven.plugins:maven-clean-plugin:2.4:jar:javadoc
-     * </pre>
-     *
-     * If the type is 'maven-plugin' the plugin will try to resolve the artifact using plugin remote repositories,
-     * instead of using artifact remote repositories.
-     *
-     * @since 1.6
-     */
-    @Parameter
-    private String[] extraArtifacts;
-
-    /**
-     */
-    @Component
-    private DependencyResolver resolver;
-
-    private ProjectBuildingRequest projectBuildingRequest;
-
-    /**
-     * Performs this mojo's tasks.
-     *
-     * @throws MojoExecutionException If the artifacts could not be installed.
-     */
-    public void execute()
-        throws MojoExecutionException
-    {
-        if ( skipInstallation )
-        {
-            getLog().info( "Skipping artifact installation per configuration." );
-            return;
-        }
-
-        createTestRepository();
-
-        installedArtifacts = new HashSet<String>();
-        copiedArtifacts = new HashSet<String>();
-
-        installProjectDependencies( project, reactorProjects );
-        installProjectParents( project );
-        installProjectArtifacts( project );
-
-        installExtraArtifacts( extraArtifacts );
-    }
-
-    /**
-     * Creates the local repository for the integration tests. If the user specified a custom repository location, the
-     * custom repository will have the same identifier, layout and policies as the real local repository. That means
-     * apart from the location, the custom repository will be indistinguishable from the real repository such that its
-     * usage is transparent to the integration tests.
-     *
-     * @return The local repository for the integration tests, never <code>null</code>.
-     * @throws MojoExecutionException If the repository could not be created.
-     */
-    private void createTestRepository()
-        throws MojoExecutionException
-    {
-        
-        if ( !localRepositoryPath.exists() && !localRepositoryPath.mkdirs() )
-        {
-            throw new MojoExecutionException( "Failed to create directory: " + localRepositoryPath );
-        }
-        projectBuildingRequest =
-            repositoryManager.setLocalRepositoryBasedir( session.getProjectBuildingRequest(), localRepositoryPath );
-    }
-
-    /**
-     * Installs the specified artifact to the local repository. Note: This method should only be used for artifacts that
-     * originate from the current (reactor) build. Artifacts that have been grabbed from the user's local repository
-     * should be installed to the test repository via {@link #copyArtifact(File, Artifact)}.
-     *
-     * @param file The file associated with the artifact, must not be <code>null</code>. This is in most cases the value
-     *            of <code>artifact.getFile()</code> with the exception of the main artifact from a project with
-     *            packaging "pom". Projects with packaging "pom" have no main artifact file. They have however artifact
-     *            metadata (e.g. site descriptors) which needs to be installed.
-     * @param artifact The artifact to install, must not be <code>null</code>.
-     * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file).
-     */
-    private void installArtifact( File file, Artifact artifact )
-        throws MojoExecutionException
-    {
-        try
-        {
-            if ( file == null )
-            {
-                throw new IllegalStateException( "Artifact has no associated file: " + artifact.getId() );
-            }
-            if ( !file.isFile() )
-            {
-                throw new IllegalStateException( "Artifact is not fully assembled: " + file );
-            }
-
-            if ( installedArtifacts.add( artifact.getId() ) )
-            {
-                artifact.setFile( file );
-                installer.install( projectBuildingRequest, localRepositoryPath,
-                                   Collections.singletonList( artifact ) );
-            }
-            else
-            {
-                getLog().debug( "Not re-installing " + artifact + ", " + file );
-            }
-        }
-        catch ( Exception e )
-        {
-            throw new MojoExecutionException( "Failed to install artifact: " + artifact, e );
-        }
-    }
-
-    /**
-     * Installs the specified artifact to the local repository. This method serves basically the same purpose as
-     * {@link #installArtifact(File, Artifact)} but is meant for artifacts that have been resolved
-     * from the user's local repository (and not the current build outputs). The subtle difference here is that
-     * artifacts from the repository have already undergone transformations and these manipulations should not be redone
-     * by the artifact installer. For this reason, this method performs plain copy operations to install the artifacts.
-     *
-     * @param file The file associated with the artifact, must not be <code>null</code>.
-     * @param artifact The artifact to install, must not be <code>null</code>.
-     * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file).
-     */
-    private void copyArtifact( File file, Artifact artifact )
-        throws MojoExecutionException
-    {
-        try
-        {
-            if ( file == null )
-            {
-                throw new IllegalStateException( "Artifact has no associated file: " + artifact.getId() );
-            }
-            if ( !file.isFile() )
-            {
-                throw new IllegalStateException( "Artifact is not fully assembled: " + file );
-            }
-
-            if ( copiedArtifacts.add( artifact.getId() ) )
-            {
-                File destination =
-                    new File( localRepositoryPath,
-                              repositoryManager.getPathForLocalArtifact( projectBuildingRequest, artifact ) );
-
-                getLog().debug( "Installing " + file + " to " + destination );
-
-                copyFileIfDifferent( file, destination );
-
-                MetadataUtils.createMetadata( destination, artifact );
-            }
-            else
-            {
-                getLog().debug( "Not re-installing " + artifact + ", " + file );
-            }
-        }
-        catch ( Exception e )
-        {
-            throw new MojoExecutionException( "Failed to stage artifact: " + artifact, e );
-        }
-    }
-
-    private void copyFileIfDifferent( File src, File dst )
-        throws IOException
-    {
-        if ( src.lastModified() != dst.lastModified() || src.length() != dst.length() )
-        {
-            FileUtils.copyFile( src, dst );
-            dst.setLastModified( src.lastModified() );
-        }
-    }
-
-    /**
-     * Installs the main artifact and any attached artifacts of the specified project to the local repository.
-     *
-     * @param mvnProject The project whose artifacts should be installed, must not be <code>null</code>.
-     * @throws MojoExecutionException If any artifact could not be installed.
-     */
-    private void installProjectArtifacts( MavenProject mvnProject )
-        throws MojoExecutionException
-    {
-        try
-        {
-            // Install POM (usually attached as metadata but that happens only as a side effect of the Install Plugin)
-            installProjectPom( mvnProject );
-
-            // Install the main project artifact (if the project has one, e.g. has no "pom" packaging)
-            Artifact mainArtifact = mvnProject.getArtifact();
-            if ( mainArtifact.getFile() != null )
-            {
-                installArtifact( mainArtifact.getFile(), mainArtifact );
-            }
-
-            // Install any attached project artifacts
-            Collection<Artifact> attachedArtifacts = (Collection<Artifact>) mvnProject.getAttachedArtifacts();
-            for ( Artifact attachedArtifact : attachedArtifacts )
-            {
-                installArtifact( attachedArtifact.getFile(), attachedArtifact );
-            }
-        }
-        catch ( Exception e )
-        {
-            throw new MojoExecutionException( "Failed to install project artifacts: " + mvnProject, e );
-        }
-    }
-
-    /**
-     * Installs the (locally reachable) parent POMs of the specified project to the local repository. The parent POMs
-     * from the reactor must be installed or the forked IT builds will fail when using a clean repository.
-     *
-     * @param mvnProject The project whose parent POMs should be installed, must not be <code>null</code>.
-     * @throws MojoExecutionException If any POM could not be installed.
-     */
-    private void installProjectParents( MavenProject mvnProject )
-        throws MojoExecutionException
-    {
-        try
-        {
-            for ( MavenProject parent = mvnProject.getParent(); parent != null; parent = parent.getParent() )
-            {
-                if ( parent.getFile() == null )
-                {
-                    copyParentPoms( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
-                    break;
-                }
-                installProjectPom( parent );
-            }
-        }
-        catch ( Exception e )
-        {
-            throw new MojoExecutionException( "Failed to install project parents: " + mvnProject, e );
-        }
-    }
-
-    /**
-     * Installs the POM of the specified project to the local repository.
-     *
-     * @param mvnProject The project whose POM should be installed, must not be <code>null</code>.
-     * @throws MojoExecutionException If the POM could not be installed.
-     */
-    private void installProjectPom( MavenProject mvnProject )
-        throws MojoExecutionException
-    {
-        try
-        {
-            Artifact pomArtifact = null;
-            if ( "pom".equals( mvnProject.getPackaging() ) )
-            {
-                pomArtifact = mvnProject.getArtifact();
-            }
-            if ( pomArtifact == null )
-            {
-                pomArtifact =
-                    artifactFactory.createProjectArtifact( mvnProject.getGroupId(), mvnProject.getArtifactId(),
-                                                           mvnProject.getVersion() );
-            }
-            installArtifact( mvnProject.getFile(), pomArtifact );
-        }
-        catch ( Exception e )
-        {
-            throw new MojoExecutionException( "Failed to install POM: " + mvnProject, e );
-        }
-    }
-
-    /**
-     * Installs the dependent projects from the reactor to the local repository. The dependencies on other modules from
-     * the reactor must be installed or the forked IT builds will fail when using a clean repository.
-     *
-     * @param mvnProject The project whose dependent projects should be installed, must not be <code>null</code>.
-     * @param reactorProjects The set of projects in the reactor build, must not be <code>null</code>.
-     * @throws MojoExecutionException If any dependency could not be installed.
-     */
-    private void installProjectDependencies( MavenProject mvnProject, Collection<MavenProject> reactorProjects )
-        throws MojoExecutionException
-    {
-        // keep track if we have passed mvnProject in reactorProjects
-        boolean foundCurrent = false;
-
-        // ... into dependencies that were resolved from reactor projects ...
-        Collection<String> dependencyProjects = new LinkedHashSet<String>();
-
-        // index available reactor projects
-        Map<String, MavenProject> projects = new HashMap<String, MavenProject>( reactorProjects.size() );
-        for ( MavenProject reactorProject : reactorProjects )
-        {
-            String projectId =
-                reactorProject.getGroupId() + ':' + reactorProject.getArtifactId() + ':' + reactorProject.getVersion();
-
-            projects.put( projectId, reactorProject );
-
-            // only add projects of reactor build previous to this mvnProject
-            foundCurrent |= ( mvnProject.equals( reactorProject ) );
-            if ( !foundCurrent )
-            {
-                dependencyProjects.add( projectId );
-            }
-        }
-
-        // group transitive dependencies (even those that don't contribute to the class path like POMs) ...
-        Collection<Artifact> artifacts = (Collection<Artifact>) mvnProject.getArtifacts();
-        // ... and those that were resolved from the (local) repo
-        Collection<Artifact> dependencyArtifacts = new LinkedHashSet<Artifact>();
-
-        for ( Artifact artifact : artifacts )
-        {
-            // workaround for MNG-2961 to ensure the base version does not contain a timestamp
-            artifact.isSnapshot();
-
-            String projectId = artifact.getGroupId() + ':' + artifact.getArtifactId() + ':' + artifact.getBaseVersion();
-
-            if ( !projects.containsKey( projectId ) )
-            {
-                dependencyArtifacts.add( artifact );
-            }
-        }
-
-        // install dependencies
-        try
-        {
-            // copy dependencies that where resolved from the local repo
-            for ( Artifact artifact : dependencyArtifacts )
-            {
-                copyArtifact( artifact );
-            }
-
-            // install dependencies that were resolved from the reactor
-            for ( String projectId : dependencyProjects )
-            {
-                MavenProject dependencyProject = projects.get( projectId );
-
-                installProjectArtifacts( dependencyProject );
-                installProjectParents( dependencyProject );
-            }
-        }
-        catch ( Exception e )
-        {
-            throw new MojoExecutionException( "Failed to install project dependencies: " + mvnProject, e );
-        }
-    }
-
-    private void copyArtifact( Artifact artifact )
-        throws MojoExecutionException
-    {
-        copyPoms( artifact );
-
-        Artifact depArtifact =
-            artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(),
-                                                          artifact.getBaseVersion(), artifact.getType(),
-                                                          artifact.getClassifier() );
-
-        File artifactFile = artifact.getFile();
-
-        copyArtifact( artifactFile, depArtifact );
-    }
-
-    private void copyPoms( Artifact artifact )
-        throws MojoExecutionException
-    {
-        Artifact pomArtifact =
-            artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
-                                                   artifact.getBaseVersion() );
-
-        File pomFile = new File( localRepository.getBasedir(), localRepository.pathOf( pomArtifact ) );
-
-        if ( pomFile.isFile() )
-        {
-            copyArtifact( pomFile, pomArtifact );
-            copyParentPoms( pomFile );
-        }
-    }
-
-    /**
-     * Installs all parent POMs of the specified POM file that are available in the local repository.
-     *
-     * @param pomFile The path to the POM file whose parents should be installed, must not be <code>null</code>.
-     * @throws MojoExecutionException If any (existing) parent POM could not be installed.
-     */
-    private void copyParentPoms( File pomFile )
-        throws MojoExecutionException
-    {
-        Model model = PomUtils.loadPom( pomFile );
-        Parent parent = model.getParent();
-        if ( parent != null )
-        {
-            copyParentPoms( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
-        }
-    }
-
-    /**
-     * Installs the specified POM and all its parent POMs to the local repository.
-     *
-     * @param groupId The group id of the POM which should be installed, must not be <code>null</code>.
-     * @param artifactId The artifact id of the POM which should be installed, must not be <code>null</code>.
-     * @param version The version of the POM which should be installed, must not be <code>null</code>.
-     * @throws MojoExecutionException If any (existing) parent POM could not be installed.
-     */
-    private void copyParentPoms( String groupId, String artifactId, String version )
-        throws MojoExecutionException
-    {
-        Artifact pomArtifact = artifactFactory.createProjectArtifact( groupId, artifactId, version );
-
-        if ( installedArtifacts.contains( pomArtifact.getId() ) || copiedArtifacts.contains( pomArtifact.getId() ) )
-        {
-            getLog().debug( "Not re-installing " + pomArtifact );
-            return;
-        }
-
-        File pomFile = new File( localRepository.getBasedir(), localRepository.pathOf( pomArtifact ) );
-        if ( pomFile.isFile() )
-        {
-            copyArtifact( pomFile, pomArtifact );
-            copyParentPoms( pomFile );
-        }
-    }
-
-    private void installExtraArtifacts( String[] extraArtifacts )
-        throws MojoExecutionException
-    {
-        if ( extraArtifacts == null )
-        {
-            return;
-        }
-
-        for ( String extraArtifact : extraArtifacts )
-        {
-            String[] gav = extraArtifact.split( ":" );
-            if ( gav.length < 3 || gav.length > 5 )
-            {
-                throw new MojoExecutionException( "Invalid artifact " + extraArtifact );
-            }
-
-            String groupId = gav[0];
-            String artifactId = gav[1];
-            String version = gav[2];
-
-            String type = "jar";
-            if ( gav.length > 3 )
-            {
-                type = gav[3];
-            }
-
-            String classifier = null;
-            if ( gav.length == 5 )
-            {
-                classifier = gav[4];
-            }
-
-            DefaultDependableCoordinate coordinate = new DefaultDependableCoordinate();
-            try
-            {
-                coordinate.setGroupId( groupId );
-                coordinate.setArtifactId( artifactId );
-                coordinate.setVersion( version );
-                coordinate.setType( type );
-                coordinate.setClassifier( classifier );
-
-                resolver.resolveDependencies( projectBuildingRequest, coordinate, null );
-            }
-            catch ( DependencyResolverException e )
-            {
-                throw new MojoExecutionException( "Unable to resolve dependencies for: " + coordinate, e );
-            }
-        }
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.IOException;

+import java.util.Collection;

+import java.util.Collections;

+import java.util.HashMap;

+import java.util.HashSet;

+import java.util.LinkedHashSet;

+import java.util.Map;

+

+import org.apache.maven.artifact.Artifact;

+import org.apache.maven.artifact.factory.ArtifactFactory;

+import org.apache.maven.artifact.repository.ArtifactRepository;

+import org.apache.maven.execution.MavenSession;

+import org.apache.maven.model.Model;

+import org.apache.maven.model.Parent;

+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.plugins.annotations.ResolutionScope;

+import org.apache.maven.project.MavenProject;

+import org.apache.maven.project.ProjectBuildingRequest;

+import org.apache.maven.shared.artifact.install.ArtifactInstaller;

+import org.apache.maven.shared.dependencies.DefaultDependableCoordinate;

+import org.apache.maven.shared.dependencies.resolve.DependencyResolver;

+import org.apache.maven.shared.dependencies.resolve.DependencyResolverException;

+import org.apache.maven.shared.repository.RepositoryManager;

+import org.codehaus.plexus.util.FileUtils;

+

+/**

+ * Installs the project artifacts of the main build into the local repository as a preparation to run the sub projects.

+ * More precisely, all artifacts of the project itself, all its locally reachable parent POMs and all its dependencies

+ * from the reactor will be installed to the local repository.

+ *

+ * @since 1.2

+ * @author Paul Gier

+ * @author Benjamin Bentmann

+ * @version $Id: InstallMojo.java 1748000 2016-06-12 13:20:59Z rfscholte $

+ */

+// CHECKSTYLE_OFF: LineLength

+@Mojo( name = "install", defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true )

+// CHECKSTYLE_ON: LineLength

+public class InstallMojo

+    extends AbstractMojo

+{

+

+    /**

+     * Maven artifact install component to copy artifacts to the local repository.

+     */

+    @Component

+    private ArtifactInstaller installer;

+    

+    @Component

+    private RepositoryManager repositoryManager;

+

+    /**

+     * The component used to create artifacts.

+     */

+    @Component

+    private ArtifactFactory artifactFactory;

+

+    /**

+     */

+    @Parameter( property = "localRepository", required = true, readonly = true )

+    private ArtifactRepository localRepository;

+

+    /**

+     * The path to the local repository into which the project artifacts should be installed for the integration tests.

+     * If not set, the regular local repository will be used. To prevent soiling of your regular local repository with

+     * possibly broken artifacts, it is strongly recommended to use an isolated repository for the integration tests

+     * (e.g. <code>${project.build.directory}/it-repo</code>).

+     */

+    @Parameter( property = "invoker.localRepositoryPath", 

+                defaultValue = "${session.localRepository.basedir}", required = true )

+    private File localRepositoryPath;

+

+    /**

+     * The current Maven project.

+     */

+    @Parameter( defaultValue = "${project}", readonly = true, required = true )

+    private MavenProject project;

+

+    @Parameter( defaultValue = "${session}", readonly = true, required = true )

+    private MavenSession session;

+    

+    /**

+     * The set of Maven projects in the reactor build.

+     */

+    @Parameter( defaultValue = "${reactorProjects}", readonly = true )

+    private Collection<MavenProject> reactorProjects;

+

+    /**

+     * A flag used to disable the installation procedure. This is primarily intended for usage from the command line to

+     * occasionally adjust the build.

+     *

+     * @since 1.4

+     */

+    @Parameter( property = "invoker.skip", defaultValue = "false" )

+    private boolean skipInstallation;

+

+    /**

+     * The identifiers of already installed artifacts, used to avoid multiple installation of the same artifact.

+     */

+    private Collection<String> installedArtifacts;

+

+    /**

+     * The identifiers of already copied artifacts, used to avoid multiple installation of the same artifact.

+     */

+    private Collection<String> copiedArtifacts;

+

+    /**

+     * Extra dependencies that need to be installed on the local repository.<BR>

+     * Format:

+     *

+     * <pre>

+     * groupId:artifactId:version:type:classifier

+     * </pre>

+     *

+     * Examples:

+     *

+     * <pre>

+     * org.apache.maven.plugins:maven-clean-plugin:2.4:maven-plugin

+     * org.apache.maven.plugins:maven-clean-plugin:2.4:jar:javadoc

+     * </pre>

+     *

+     * If the type is 'maven-plugin' the plugin will try to resolve the artifact using plugin remote repositories,

+     * instead of using artifact remote repositories.

+     *

+     * @since 1.6

+     */

+    @Parameter

+    private String[] extraArtifacts;

+

+    /**

+     */

+    @Component

+    private DependencyResolver resolver;

+

+    private ProjectBuildingRequest projectBuildingRequest;

+

+    /**

+     * Performs this mojo's tasks.

+     *

+     * @throws MojoExecutionException If the artifacts could not be installed.

+     */

+    public void execute()

+        throws MojoExecutionException

+    {

+        if ( skipInstallation )

+        {

+            getLog().info( "Skipping artifact installation per configuration." );

+            return;

+        }

+

+        createTestRepository();

+

+        installedArtifacts = new HashSet<String>();

+        copiedArtifacts = new HashSet<String>();

+

+        installProjectDependencies( project, reactorProjects );

+        installProjectParents( project );

+        installProjectArtifacts( project );

+

+        installExtraArtifacts( extraArtifacts );

+    }

+

+    /**

+     * Creates the local repository for the integration tests. If the user specified a custom repository location, the

+     * custom repository will have the same identifier, layout and policies as the real local repository. That means

+     * apart from the location, the custom repository will be indistinguishable from the real repository such that its

+     * usage is transparent to the integration tests.

+     *

+     * @return The local repository for the integration tests, never <code>null</code>.

+     * @throws MojoExecutionException If the repository could not be created.

+     */

+    private void createTestRepository()

+        throws MojoExecutionException

+    {

+        

+        if ( !localRepositoryPath.exists() && !localRepositoryPath.mkdirs() )

+        {

+            throw new MojoExecutionException( "Failed to create directory: " + localRepositoryPath );

+        }

+        projectBuildingRequest =

+            repositoryManager.setLocalRepositoryBasedir( session.getProjectBuildingRequest(), localRepositoryPath );

+    }

+

+    /**

+     * Installs the specified artifact to the local repository. Note: This method should only be used for artifacts that

+     * originate from the current (reactor) build. Artifacts that have been grabbed from the user's local repository

+     * should be installed to the test repository via {@link #copyArtifact(File, Artifact)}.

+     *

+     * @param file The file associated with the artifact, must not be <code>null</code>. This is in most cases the value

+     *            of <code>artifact.getFile()</code> with the exception of the main artifact from a project with

+     *            packaging "pom". Projects with packaging "pom" have no main artifact file. They have however artifact

+     *            metadata (e.g. site descriptors) which needs to be installed.

+     * @param artifact The artifact to install, must not be <code>null</code>.

+     * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file).

+     */

+    private void installArtifact( File file, Artifact artifact )

+        throws MojoExecutionException

+    {

+        try

+        {

+            if ( file == null )

+            {

+                throw new IllegalStateException( "Artifact has no associated file: " + artifact.getId() );

+            }

+            if ( !file.isFile() )

+            {

+                throw new IllegalStateException( "Artifact is not fully assembled: " + file );

+            }

+

+            if ( installedArtifacts.add( artifact.getId() ) )

+            {

+                artifact.setFile( file );

+                installer.install( projectBuildingRequest, localRepositoryPath,

+                                   Collections.singletonList( artifact ) );

+            }

+            else

+            {

+                getLog().debug( "Not re-installing " + artifact + ", " + file );

+            }

+        }

+        catch ( Exception e )

+        {

+            throw new MojoExecutionException( "Failed to install artifact: " + artifact, e );

+        }

+    }

+

+    /**

+     * Installs the specified artifact to the local repository. This method serves basically the same purpose as

+     * {@link #installArtifact(File, Artifact)} but is meant for artifacts that have been resolved

+     * from the user's local repository (and not the current build outputs). The subtle difference here is that

+     * artifacts from the repository have already undergone transformations and these manipulations should not be redone

+     * by the artifact installer. For this reason, this method performs plain copy operations to install the artifacts.

+     *

+     * @param file The file associated with the artifact, must not be <code>null</code>.

+     * @param artifact The artifact to install, must not be <code>null</code>.

+     * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file).

+     */

+    private void copyArtifact( File file, Artifact artifact )

+        throws MojoExecutionException

+    {

+        try

+        {

+            if ( file == null )

+            {

+                throw new IllegalStateException( "Artifact has no associated file: " + artifact.getId() );

+            }

+            if ( !file.isFile() )

+            {

+                throw new IllegalStateException( "Artifact is not fully assembled: " + file );

+            }

+

+            if ( copiedArtifacts.add( artifact.getId() ) )

+            {

+                File destination =

+                    new File( localRepositoryPath,

+                              repositoryManager.getPathForLocalArtifact( projectBuildingRequest, artifact ) );

+

+                getLog().debug( "Installing " + file + " to " + destination );

+

+                copyFileIfDifferent( file, destination );

+

+                MetadataUtils.createMetadata( destination, artifact );

+            }

+            else

+            {

+                getLog().debug( "Not re-installing " + artifact + ", " + file );

+            }

+        }

+        catch ( Exception e )

+        {

+            throw new MojoExecutionException( "Failed to stage artifact: " + artifact, e );

+        }

+    }

+

+    private void copyFileIfDifferent( File src, File dst )

+        throws IOException

+    {

+        if ( src.lastModified() != dst.lastModified() || src.length() != dst.length() )

+        {

+            FileUtils.copyFile( src, dst );

+            dst.setLastModified( src.lastModified() );

+        }

+    }

+

+    /**

+     * Installs the main artifact and any attached artifacts of the specified project to the local repository.

+     *

+     * @param mvnProject The project whose artifacts should be installed, must not be <code>null</code>.

+     * @throws MojoExecutionException If any artifact could not be installed.

+     */

+    private void installProjectArtifacts( MavenProject mvnProject )

+        throws MojoExecutionException

+    {

+        try

+        {

+            // Install POM (usually attached as metadata but that happens only as a side effect of the Install Plugin)

+            installProjectPom( mvnProject );

+

+            // Install the main project artifact (if the project has one, e.g. has no "pom" packaging)

+            Artifact mainArtifact = mvnProject.getArtifact();

+            if ( mainArtifact.getFile() != null )

+            {

+                installArtifact( mainArtifact.getFile(), mainArtifact );

+            }

+

+            // Install any attached project artifacts

+            Collection<Artifact> attachedArtifacts = (Collection<Artifact>) mvnProject.getAttachedArtifacts();

+            for ( Artifact attachedArtifact : attachedArtifacts )

+            {

+                installArtifact( attachedArtifact.getFile(), attachedArtifact );

+            }

+        }

+        catch ( Exception e )

+        {

+            throw new MojoExecutionException( "Failed to install project artifacts: " + mvnProject, e );

+        }

+    }

+

+    /**

+     * Installs the (locally reachable) parent POMs of the specified project to the local repository. The parent POMs

+     * from the reactor must be installed or the forked IT builds will fail when using a clean repository.

+     *

+     * @param mvnProject The project whose parent POMs should be installed, must not be <code>null</code>.

+     * @throws MojoExecutionException If any POM could not be installed.

+     */

+    private void installProjectParents( MavenProject mvnProject )

+        throws MojoExecutionException

+    {

+        try

+        {

+            for ( MavenProject parent = mvnProject.getParent(); parent != null; parent = parent.getParent() )

+            {

+                if ( parent.getFile() == null )

+                {

+                    copyParentPoms( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );

+                    break;

+                }

+                installProjectPom( parent );

+            }

+        }

+        catch ( Exception e )

+        {

+            throw new MojoExecutionException( "Failed to install project parents: " + mvnProject, e );

+        }

+    }

+

+    /**

+     * Installs the POM of the specified project to the local repository.

+     *

+     * @param mvnProject The project whose POM should be installed, must not be <code>null</code>.

+     * @throws MojoExecutionException If the POM could not be installed.

+     */

+    private void installProjectPom( MavenProject mvnProject )

+        throws MojoExecutionException

+    {

+        try

+        {

+            Artifact pomArtifact = null;

+            if ( "pom".equals( mvnProject.getPackaging() ) )

+            {

+                pomArtifact = mvnProject.getArtifact();

+            }

+            if ( pomArtifact == null )

+            {

+                pomArtifact =

+                    artifactFactory.createProjectArtifact( mvnProject.getGroupId(), mvnProject.getArtifactId(),

+                                                           mvnProject.getVersion() );

+            }

+            installArtifact( mvnProject.getFile(), pomArtifact );

+        }

+        catch ( Exception e )

+        {

+            throw new MojoExecutionException( "Failed to install POM: " + mvnProject, e );

+        }

+    }

+

+    /**

+     * Installs the dependent projects from the reactor to the local repository. The dependencies on other modules from

+     * the reactor must be installed or the forked IT builds will fail when using a clean repository.

+     *

+     * @param mvnProject The project whose dependent projects should be installed, must not be <code>null</code>.

+     * @param reactorProjects The set of projects in the reactor build, must not be <code>null</code>.

+     * @throws MojoExecutionException If any dependency could not be installed.

+     */

+    private void installProjectDependencies( MavenProject mvnProject, Collection<MavenProject> reactorProjects )

+        throws MojoExecutionException

+    {

+        // keep track if we have passed mvnProject in reactorProjects

+        boolean foundCurrent = false;

+

+        // ... into dependencies that were resolved from reactor projects ...

+        Collection<String> dependencyProjects = new LinkedHashSet<String>();

+

+        // index available reactor projects

+        Map<String, MavenProject> projects = new HashMap<String, MavenProject>( reactorProjects.size() );

+        for ( MavenProject reactorProject : reactorProjects )

+        {

+            String projectId =

+                reactorProject.getGroupId() + ':' + reactorProject.getArtifactId() + ':' + reactorProject.getVersion();

+

+            projects.put( projectId, reactorProject );

+

+            // only add projects of reactor build previous to this mvnProject

+            foundCurrent |= ( mvnProject.equals( reactorProject ) );

+            if ( !foundCurrent )

+            {

+                dependencyProjects.add( projectId );

+            }

+        }

+

+        // group transitive dependencies (even those that don't contribute to the class path like POMs) ...

+        Collection<Artifact> artifacts = (Collection<Artifact>) mvnProject.getArtifacts();

+        // ... and those that were resolved from the (local) repo

+        Collection<Artifact> dependencyArtifacts = new LinkedHashSet<Artifact>();

+

+        for ( Artifact artifact : artifacts )

+        {

+            // workaround for MNG-2961 to ensure the base version does not contain a timestamp

+            artifact.isSnapshot();

+

+            String projectId = artifact.getGroupId() + ':' + artifact.getArtifactId() + ':' + artifact.getBaseVersion();

+

+            if ( !projects.containsKey( projectId ) )

+            {

+                dependencyArtifacts.add( artifact );

+            }

+        }

+

+        // install dependencies

+        try

+        {

+            // copy dependencies that where resolved from the local repo

+            for ( Artifact artifact : dependencyArtifacts )

+            {

+                copyArtifact( artifact );

+            }

+

+            // install dependencies that were resolved from the reactor

+            for ( String projectId : dependencyProjects )

+            {

+                MavenProject dependencyProject = projects.get( projectId );

+

+                installProjectArtifacts( dependencyProject );

+                installProjectParents( dependencyProject );

+            }

+        }

+        catch ( Exception e )

+        {

+            throw new MojoExecutionException( "Failed to install project dependencies: " + mvnProject, e );

+        }

+    }

+

+    private void copyArtifact( Artifact artifact )

+        throws MojoExecutionException

+    {

+        copyPoms( artifact );

+

+        Artifact depArtifact =

+            artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(),

+                                                          artifact.getBaseVersion(), artifact.getType(),

+                                                          artifact.getClassifier() );

+

+        File artifactFile = artifact.getFile();

+

+        copyArtifact( artifactFile, depArtifact );

+    }

+

+    private void copyPoms( Artifact artifact )

+        throws MojoExecutionException

+    {

+        Artifact pomArtifact =

+            artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),

+                                                   artifact.getBaseVersion() );

+

+        File pomFile = new File( localRepository.getBasedir(), localRepository.pathOf( pomArtifact ) );

+

+        if ( pomFile.isFile() )

+        {

+            copyArtifact( pomFile, pomArtifact );

+            copyParentPoms( pomFile );

+        }

+    }

+

+    /**

+     * Installs all parent POMs of the specified POM file that are available in the local repository.

+     *

+     * @param pomFile The path to the POM file whose parents should be installed, must not be <code>null</code>.

+     * @throws MojoExecutionException If any (existing) parent POM could not be installed.

+     */

+    private void copyParentPoms( File pomFile )

+        throws MojoExecutionException

+    {

+        Model model = PomUtils.loadPom( pomFile );

+        Parent parent = model.getParent();

+        if ( parent != null )

+        {

+            copyParentPoms( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );

+        }

+    }

+

+    /**

+     * Installs the specified POM and all its parent POMs to the local repository.

+     *

+     * @param groupId The group id of the POM which should be installed, must not be <code>null</code>.

+     * @param artifactId The artifact id of the POM which should be installed, must not be <code>null</code>.

+     * @param version The version of the POM which should be installed, must not be <code>null</code>.

+     * @throws MojoExecutionException If any (existing) parent POM could not be installed.

+     */

+    private void copyParentPoms( String groupId, String artifactId, String version )

+        throws MojoExecutionException

+    {

+        Artifact pomArtifact = artifactFactory.createProjectArtifact( groupId, artifactId, version );

+

+        if ( installedArtifacts.contains( pomArtifact.getId() ) || copiedArtifacts.contains( pomArtifact.getId() ) )

+        {

+            getLog().debug( "Not re-installing " + pomArtifact );

+            return;

+        }

+

+        File pomFile = new File( localRepository.getBasedir(), localRepository.pathOf( pomArtifact ) );

+        if ( pomFile.isFile() )

+        {

+            copyArtifact( pomFile, pomArtifact );

+            copyParentPoms( pomFile );

+        }

+    }

+

+    private void installExtraArtifacts( String[] extraArtifacts )

+        throws MojoExecutionException

+    {

+        if ( extraArtifacts == null )

+        {

+            return;

+        }

+

+        for ( String extraArtifact : extraArtifacts )

+        {

+            String[] gav = extraArtifact.split( ":" );

+            if ( gav.length < 3 || gav.length > 5 )

+            {

+                throw new MojoExecutionException( "Invalid artifact " + extraArtifact );

+            }

+

+            String groupId = gav[0];

+            String artifactId = gav[1];

+            String version = gav[2];

+

+            String type = "jar";

+            if ( gav.length > 3 )

+            {

+                type = gav[3];

+            }

+

+            String classifier = null;

+            if ( gav.length == 5 )

+            {

+                classifier = gav[4];

+            }

+

+            DefaultDependableCoordinate coordinate = new DefaultDependableCoordinate();

+            try

+            {

+                coordinate.setGroupId( groupId );

+                coordinate.setArtifactId( artifactId );

+                coordinate.setVersion( version );

+                coordinate.setType( type );

+                coordinate.setClassifier( classifier );

+

+                resolver.resolveDependencies( projectBuildingRequest, coordinate, null );

+            }

+            catch ( DependencyResolverException e )

+            {

+                throw new MojoExecutionException( "Unable to resolve dependencies for: " + coordinate, e );

+            }

+        }

+    }

+

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/IntegrationTestMojo.java b/src/main/java/org/apache/maven/plugins/invoker/IntegrationTestMojo.java
similarity index 93%
rename from src/main/java/org/apache/maven/plugin/invoker/IntegrationTestMojo.java
rename to src/main/java/org/apache/maven/plugins/invoker/IntegrationTestMojo.java
index 4f8eb72..07d76a6 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/IntegrationTestMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/IntegrationTestMojo.java
@@ -1,48 +1,48 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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 org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugins.annotations.LifecyclePhase;
-import org.apache.maven.plugins.annotations.Mojo;
-import org.apache.maven.plugins.annotations.ResolutionScope;
-
-/**
- * Searches for integration test Maven projects, and executes each, collecting a log in the project directory, will
- * never fail the build, designed to be used in conjunction with the verify mojo.
- *
- * @since 1.4
- * @author <a href="mailto:stephenconnolly at codehaus">Stephen Connolly</a>
- * @version $Id$
- */
-// CHECKSTYLE_OFF: LineLength
-@Mojo( name = "integration-test", defaultPhase = LifecyclePhase.INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true )
-public class IntegrationTestMojo
-    extends AbstractInvokerMojo
-{
-
-    void processResults( InvokerSession invokerSession )
-        throws MojoFailureException
-    {
-        // do nothing
-    }
-
-}
-// CHECKSTYLE_ON: LineLength
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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 org.apache.maven.plugin.MojoFailureException;

+import org.apache.maven.plugins.annotations.LifecyclePhase;

+import org.apache.maven.plugins.annotations.Mojo;

+import org.apache.maven.plugins.annotations.ResolutionScope;

+

+/**

+ * Searches for integration test Maven projects, and executes each, collecting a log in the project directory, will

+ * never fail the build, designed to be used in conjunction with the verify mojo.

+ *

+ * @since 1.4

+ * @author <a href="mailto:stephenconnolly at codehaus">Stephen Connolly</a>

+ * @version $Id: IntegrationTestMojo.java 1637968 2014-11-10 20:02:25Z khmarbaise $

+ */

+// CHECKSTYLE_OFF: LineLength

+@Mojo( name = "integration-test", defaultPhase = LifecyclePhase.INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true )

+public class IntegrationTestMojo

+    extends AbstractInvokerMojo

+{

+

+    void processResults( InvokerSession invokerSession )

+        throws MojoFailureException

+    {

+        // do nothing

+    }

+

+}

+// CHECKSTYLE_ON: LineLength

diff --git a/src/main/java/org/apache/maven/plugin/invoker/InvokerMojo.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerMojo.java
similarity index 95%
rename from src/main/java/org/apache/maven/plugin/invoker/InvokerMojo.java
rename to src/main/java/org/apache/maven/plugins/invoker/InvokerMojo.java
index a4d7813..2b36291 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/InvokerMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerMojo.java
@@ -1,82 +1,82 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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 org.apache.maven.plugin.MojoFailureException;
-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.plugins.annotations.ResolutionScope;
-
-/**
- * Searches for integration test Maven projects, and executes each, collecting a log in the project directory, and
- * outputting the results to the command line.
- *
- * @since 1.0
- * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
- * @author <a href="mailto:jdcasey@apache.org">John Casey</a>
- * @version $Id$
- */
-// CHECKSTYLE_OFF: LineLength
-@Mojo( name = "run", defaultPhase = LifecyclePhase.INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true )
-// CHECKSTYLE_ON: LineLength
-public class InvokerMojo
-    extends AbstractInvokerMojo
-{
-
-    /**
-     * A flag controlling whether failures of the sub builds should fail the main build, too. If set to
-     * <code>true</code>, the main build will proceed even if one or more sub builds failed.
-     *
-     * @since 1.3
-     */
-    @Parameter( property = "maven.test.failure.ignore", defaultValue = "false" )
-    private boolean ignoreFailures;
-
-    /**
-     * Set this to <code>true</code> to cause a failure if there are no projects to invoke.
-     *
-     * @since 1.9
-     */
-    @Parameter( property = "invoker.failIfNoProjects" )
-    private Boolean failIfNoProjects;
-
-    void processResults( InvokerSession invokerSession )
-        throws MojoFailureException
-    {
-        if ( !suppressSummaries )
-        {
-            invokerSession.logSummary( getLog(), ignoreFailures );
-        }
-
-        invokerSession.handleFailures( getLog(), ignoreFailures );
-    }
-
-    @Override
-    protected void doFailIfNoProjects()
-        throws MojoFailureException
-    {
-        if ( Boolean.TRUE.equals( failIfNoProjects ) )
-        {
-            throw new MojoFailureException( "No projects to invoke!" );
-        }
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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 org.apache.maven.plugin.MojoFailureException;

+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.plugins.annotations.ResolutionScope;

+

+/**

+ * Searches for integration test Maven projects, and executes each, collecting a log in the project directory, and

+ * outputting the results to the command line.

+ *

+ * @since 1.0

+ * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>

+ * @author <a href="mailto:jdcasey@apache.org">John Casey</a>

+ * @version $Id: InvokerMojo.java 1637968 2014-11-10 20:02:25Z khmarbaise $

+ */

+// CHECKSTYLE_OFF: LineLength

+@Mojo( name = "run", defaultPhase = LifecyclePhase.INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true )

+// CHECKSTYLE_ON: LineLength

+public class InvokerMojo

+    extends AbstractInvokerMojo

+{

+

+    /**

+     * A flag controlling whether failures of the sub builds should fail the main build, too. If set to

+     * <code>true</code>, the main build will proceed even if one or more sub builds failed.

+     *

+     * @since 1.3

+     */

+    @Parameter( property = "maven.test.failure.ignore", defaultValue = "false" )

+    private boolean ignoreFailures;

+

+    /**

+     * Set this to <code>true</code> to cause a failure if there are no projects to invoke.

+     *

+     * @since 1.9

+     */

+    @Parameter( property = "invoker.failIfNoProjects" )

+    private Boolean failIfNoProjects;

+

+    void processResults( InvokerSession invokerSession )

+        throws MojoFailureException

+    {

+        if ( !suppressSummaries )

+        {

+            invokerSession.logSummary( getLog(), ignoreFailures );

+        }

+

+        invokerSession.handleFailures( getLog(), ignoreFailures );

+    }

+

+    @Override

+    protected void doFailIfNoProjects()

+        throws MojoFailureException

+    {

+        if ( Boolean.TRUE.equals( failIfNoProjects ) )

+        {

+            throw new MojoFailureException( "No projects to invoke!" );

+        }

+    }

+

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/InvokerProperties.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java
similarity index 98%
rename from src/main/java/org/apache/maven/plugin/invoker/InvokerProperties.java
rename to src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java
index eecab9a..97a40ee 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/InvokerProperties.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java
@@ -1,365 +1,365 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.util.ArrayList;
-import java.util.Arrays;
-import java.util.Properties;
-
-import org.apache.maven.shared.invoker.InvocationRequest;
-import org.apache.maven.shared.invoker.InvocationRequest.ReactorFailureBehavior;
-import org.codehaus.plexus.util.StringUtils;
-
-/**
- * Provides a convenient facade around the <code>invoker.properties</code>.
- *
- * @author Benjamin Bentmann
- * @version $Id$
- */
-class InvokerProperties
-{
-    private static final String SELECTOR_PREFIX = "selector.";
-
-    private enum InvocationProperty
-    {
-        PROJECT( "invoker.project" ),
-        GOALS( "invoker.goals" ),
-        PROFILES( "invoker.profiles" ),
-        MAVEN_OPTS( "invoker.mavenOpts" ),
-        FAILURE_BEHAVIOR( "invoker.failureBehavior" ),
-        NON_RECURSIVE( "invoker.nonRecursive" ),
-        OFFLINE( "invoker.offline" ),
-        SYSTEM_PROPERTIES_FILE( "invoker.systemPropertiesFile" ),
-        DEBUG( "invoker.debug" );
-
-        private final String key;
-
-        private InvocationProperty( final String s )
-        {
-            this.key = s;
-        }
-
-        @Override
-        public String toString()
-        {
-            return key;
-        }
-    }
-    
-    private enum SelectorProperty
-    {
-        JAVA_VERSION( ".java.version" ),
-        MAVEN_VERSION( ".maven.version" ),
-        OS_FAMLY( ".os.family" );
-        
-        private final String suffix;
-        
-        private SelectorProperty( String suffix )
-        {
-            this.suffix = suffix;
-        }
-        
-        @Override
-        public String toString()
-        {
-            return suffix;
-        }
-    }
-
-    /**
-     * The invoker properties being wrapped.
-     */
-    private final Properties properties;
-
-    /**
-     * Creates a new facade for the specified invoker properties. The properties will not be copied, so any changes to
-     * them will be reflected by the facade.
-     *
-     * @param properties The invoker properties to wrap, may be <code>null</code> if none.
-     */
-    public InvokerProperties( Properties properties )
-    {
-        this.properties = ( properties != null ) ? properties : new Properties();
-    }
-
-    /**
-     * Gets the invoker properties being wrapped.
-     *
-     * @return The invoker properties being wrapped, never <code>null</code>.
-     */
-    public Properties getProperties()
-    {
-        return this.properties;
-    }
-
-    /**
-     * Gets the name of the corresponding build job.
-     *
-     * @return The name of the build job or an empty string if not set.
-     */
-    public String getJobName()
-    {
-        return this.properties.getProperty( "invoker.name", "" );
-    }
-
-    /**
-     * Gets the description of the corresponding build job.
-     *
-     * @return The description of the build job or an empty string if not set.
-     */
-    public String getJobDescription()
-    {
-        return this.properties.getProperty( "invoker.description", "" );
-    }
-
-    /**
-     * Gets the specification of JRE versions on which this build job should be run.
-     *
-     * @return The specification of JRE versions or an empty string if not set.
-     */
-    public String getJreVersion()
-    {
-        return this.properties.getProperty( "invoker.java.version", "" );
-    }
-
-    /**
-     * Gets the specification of JRE versions on which this build job should be run.
-     *
-     * @return The specification of JRE versions or an empty string if not set.
-     */
-    public String getJreVersion( int index )
-    {
-        return this.properties.getProperty( SELECTOR_PREFIX + index + SelectorProperty.JAVA_VERSION.suffix,
-                                            getJreVersion() );
-    }
-
-    /**
-     * Gets the specification of Maven versions on which this build job should be run.
-     *
-     * @return The specification of Maven versions on which this build job should be run.
-     * @since 1.5
-     */
-    public String getMavenVersion()
-    {
-        return this.properties.getProperty( "invoker.maven.version", "" );
-    }
-    
-    /**
-     * 
-     * @param index the selector index
-     * @return The specification of Maven versions on which this build job should be run.
-     * @since 3.0.0
-     */
-    public String getMavenVersion( int index )
-    {
-        return this.properties.getProperty( SELECTOR_PREFIX + index + SelectorProperty.MAVEN_VERSION.suffix,
-                                            getMavenVersion() );
-    }
-
-    /**
-     * Gets the specification of OS families on which this build job should be run.
-     *
-     * @return The specification of OS families or an empty string if not set.
-     */
-    public String getOsFamily()
-    {
-        return this.properties.getProperty( "invoker.os.family", "" );
-    }
-    
-    /**
-     * Gets the specification of OS families on which this build job should be run.
-     *
-     * @param index the selector index
-     * @return The specification of OS families or an empty string if not set.
-     * @since 3.0.0
-     */
-    public String getOsFamily( int index )
-    {
-        return this.properties.getProperty( SELECTOR_PREFIX + index + SelectorProperty.OS_FAMLY.suffix,
-                                            getOsFamily() );
-    }   
-    
-
-    /**
-     * Determines whether these invoker properties contain a build definition for the specified invocation index.
-     *
-     * @param index The one-based index of the invocation to check for, must not be negative.
-     * @return <code>true</code> if the invocation with the specified index is defined, <code>false</code> otherwise.
-     */
-    public boolean isInvocationDefined( int index )
-    {
-        for ( InvocationProperty prop : InvocationProperty.values() )
-        {
-            if ( properties.getProperty( prop.toString() + '.' + index ) != null )
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-    
-    /**
-     * Determines whether these invoker properties contain a build definition for the specified selector index.
-     * 
-     * @param index the index
-     * @return <code>true</code> if the selector with the specified index is defined, <code>false</code> otherwise.
-     * @since 3.0.0
-     */
-    public boolean isSelectorDefined( int index )
-    {
-        for ( SelectorProperty prop : SelectorProperty.values() )
-        {
-            if ( properties.getProperty( SELECTOR_PREFIX + index + prop.suffix ) != null )
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Configures the specified invocation request from these invoker properties. Settings not present in the invoker
-     * properties will be left unchanged in the invocation request.
-     *
-     * @param request The invocation request to configure, must not be <code>null</code>.
-     * @param index The one-based index of the invocation to configure, must not be negative.
-     */
-    public void configureInvocation( InvocationRequest request, int index )
-    {
-        String project = get( InvocationProperty.PROJECT, index );
-        if ( project != null )
-        {
-            File file = new File( request.getBaseDirectory(), project );
-            if ( file.isFile() )
-            {
-                request.setBaseDirectory( file.getParentFile() );
-                request.setPomFile( file );
-            }
-            else
-            {
-                request.setBaseDirectory( file );
-                request.setPomFile( null );
-            }
-        }
-
-        String goals = get( InvocationProperty.GOALS, index );
-        if ( goals != null )
-        {
-            request.setGoals( new ArrayList<String>( Arrays.asList( StringUtils.split( goals, ", \t\n\r\f" ) ) ) );
-        }
-
-        String profiles = get( InvocationProperty.PROFILES, index );
-        if ( profiles != null )
-        {
-            // CHECKSTYLE_OFF: LineLength
-            request.setProfiles( new ArrayList<String>( Arrays.asList( StringUtils.split( profiles,
-                                                                                          ", \t\n\r\f" ) ) ) );
-            // CHECKSTYLE_ON: LineLength
-        }
-
-        String mvnOpts = get( InvocationProperty.MAVEN_OPTS, index );
-        if ( mvnOpts != null )
-        {
-            request.setMavenOpts( mvnOpts );
-        }
-
-        String failureBehavior = get( InvocationProperty.FAILURE_BEHAVIOR, index );
-        if ( failureBehavior != null )
-        {
-            ReactorFailureBehavior valueOf =
-                InvocationRequest.ReactorFailureBehavior.valueOfByLongOption( failureBehavior );
-            request.setReactorFailureBehavior( valueOf );
-        }
-
-        String nonRecursive = get( InvocationProperty.NON_RECURSIVE, index );
-        if ( nonRecursive != null )
-        {
-            request.setRecursive( !Boolean.valueOf( nonRecursive ) );
-        }
-
-        String offline = get( InvocationProperty.OFFLINE, index );
-        if ( offline != null )
-        {
-            request.setOffline( Boolean.valueOf( offline ) );
-        }
-
-        String debug = get( InvocationProperty.DEBUG, index );
-        if ( debug != null )
-        {
-            request.setDebug( Boolean.valueOf( debug ) );
-        }
-    }
-
-    /**
-     * Checks whether the specified exit code matches the one expected for the given invocation.
-     *
-     * @param exitCode The exit code of the Maven invocation to check.
-     * @param index The index of the invocation for which to check the exit code, must not be negative.
-     * @return <code>true</code> if the exit code is zero and a success was expected or if the exit code is non-zero and
-     *         a failue was expected, <code>false</code> otherwise.
-     */
-    public boolean isExpectedResult( int exitCode, int index )
-    {
-        boolean nonZeroExit = "failure".equalsIgnoreCase( get( "invoker.buildResult", index ) );
-        return ( exitCode != 0 ) == nonZeroExit;
-    }
-
-    /**
-     * Gets the path to the properties file used to set the system properties for the specified invocation.
-     *
-     * @param index The index of the invocation for which to check the exit code, must not be negative.
-     * @return The path to the properties file or <code>null</code> if not set.
-     */
-    public String getSystemPropertiesFile( int index )
-    {
-        return get( InvocationProperty.SYSTEM_PROPERTIES_FILE, index );
-    }
-
-    /**
-     * Gets a value from the invoker properties. The invoker properties are intended to describe the invocation settings
-     * for multiple builds of the same project. For this reason, the properties are indexed. First, a property named
-     * <code>key.index</code> will be queried. If this property does not exist, the value of the property named
-     * <code>key</code> will finally be returned.
-     *
-     * @param key The (base) key for the invoker property to lookup, must not be <code>null</code>.
-     * @param index The index of the invocation for which to retrieve the value, must not be negative.
-     * @return The value for the requested invoker property or <code>null</code> if not defined.
-     */
-    String get( String key, int index )
-    {
-        if ( index < 0 )
-        {
-            throw new IllegalArgumentException( "invalid invocation index: " + index );
-        }
-
-        String value = properties.getProperty( key + '.' + index );
-        if ( value == null )
-        {
-            value = properties.getProperty( key );
-        }
-        return value;
-    }
-
-    private String get( InvocationProperty prop, int index )
-    {
-        return get( prop.toString(), index );
-    }
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.util.ArrayList;

+import java.util.Arrays;

+import java.util.Properties;

+

+import org.apache.maven.shared.invoker.InvocationRequest;

+import org.apache.maven.shared.invoker.InvocationRequest.ReactorFailureBehavior;

+import org.codehaus.plexus.util.StringUtils;

+

+/**

+ * Provides a convenient facade around the <code>invoker.properties</code>.

+ *

+ * @author Benjamin Bentmann

+ * @version $Id: InvokerProperties.java 1779250 2017-01-17 20:20:02Z rfscholte $

+ */

+class InvokerProperties

+{

+    private static final String SELECTOR_PREFIX = "selector.";

+

+    private enum InvocationProperty

+    {

+        PROJECT( "invoker.project" ),

+        GOALS( "invoker.goals" ),

+        PROFILES( "invoker.profiles" ),

+        MAVEN_OPTS( "invoker.mavenOpts" ),

+        FAILURE_BEHAVIOR( "invoker.failureBehavior" ),

+        NON_RECURSIVE( "invoker.nonRecursive" ),

+        OFFLINE( "invoker.offline" ),

+        SYSTEM_PROPERTIES_FILE( "invoker.systemPropertiesFile" ),

+        DEBUG( "invoker.debug" );

+

+        private final String key;

+

+        private InvocationProperty( final String s )

+        {

+            this.key = s;

+        }

+

+        @Override

+        public String toString()

+        {

+            return key;

+        }

+    }

+    

+    private enum SelectorProperty

+    {

+        JAVA_VERSION( ".java.version" ),

+        MAVEN_VERSION( ".maven.version" ),

+        OS_FAMLY( ".os.family" );

+        

+        private final String suffix;

+        

+        private SelectorProperty( String suffix )

+        {

+            this.suffix = suffix;

+        }

+        

+        @Override

+        public String toString()

+        {

+            return suffix;

+        }

+    }

+

+    /**

+     * The invoker properties being wrapped.

+     */

+    private final Properties properties;

+

+    /**

+     * Creates a new facade for the specified invoker properties. The properties will not be copied, so any changes to

+     * them will be reflected by the facade.

+     *

+     * @param properties The invoker properties to wrap, may be <code>null</code> if none.

+     */

+    public InvokerProperties( Properties properties )

+    {

+        this.properties = ( properties != null ) ? properties : new Properties();

+    }

+

+    /**

+     * Gets the invoker properties being wrapped.

+     *

+     * @return The invoker properties being wrapped, never <code>null</code>.

+     */

+    public Properties getProperties()

+    {

+        return this.properties;

+    }

+

+    /**

+     * Gets the name of the corresponding build job.

+     *

+     * @return The name of the build job or an empty string if not set.

+     */

+    public String getJobName()

+    {

+        return this.properties.getProperty( "invoker.name", "" );

+    }

+

+    /**

+     * Gets the description of the corresponding build job.

+     *

+     * @return The description of the build job or an empty string if not set.

+     */

+    public String getJobDescription()

+    {

+        return this.properties.getProperty( "invoker.description", "" );

+    }

+

+    /**

+     * Gets the specification of JRE versions on which this build job should be run.

+     *

+     * @return The specification of JRE versions or an empty string if not set.

+     */

+    public String getJreVersion()

+    {

+        return this.properties.getProperty( "invoker.java.version", "" );

+    }

+

+    /**

+     * Gets the specification of JRE versions on which this build job should be run.

+     *

+     * @return The specification of JRE versions or an empty string if not set.

+     */

+    public String getJreVersion( int index )

+    {

+        return this.properties.getProperty( SELECTOR_PREFIX + index + SelectorProperty.JAVA_VERSION.suffix,

+                                            getJreVersion() );

+    }

+

+    /**

+     * Gets the specification of Maven versions on which this build job should be run.

+     *

+     * @return The specification of Maven versions on which this build job should be run.

+     * @since 1.5

+     */

+    public String getMavenVersion()

+    {

+        return this.properties.getProperty( "invoker.maven.version", "" );

+    }

+    

+    /**

+     * 

+     * @param index the selector index

+     * @return The specification of Maven versions on which this build job should be run.

+     * @since 3.0.0

+     */

+    public String getMavenVersion( int index )

+    {

+        return this.properties.getProperty( SELECTOR_PREFIX + index + SelectorProperty.MAVEN_VERSION.suffix,

+                                            getMavenVersion() );

+    }

+

+    /**

+     * Gets the specification of OS families on which this build job should be run.

+     *

+     * @return The specification of OS families or an empty string if not set.

+     */

+    public String getOsFamily()

+    {

+        return this.properties.getProperty( "invoker.os.family", "" );

+    }

+    

+    /**

+     * Gets the specification of OS families on which this build job should be run.

+     *

+     * @param index the selector index

+     * @return The specification of OS families or an empty string if not set.

+     * @since 3.0.0

+     */

+    public String getOsFamily( int index )

+    {

+        return this.properties.getProperty( SELECTOR_PREFIX + index + SelectorProperty.OS_FAMLY.suffix,

+                                            getOsFamily() );

+    }   

+    

+

+    /**

+     * Determines whether these invoker properties contain a build definition for the specified invocation index.

+     *

+     * @param index The one-based index of the invocation to check for, must not be negative.

+     * @return <code>true</code> if the invocation with the specified index is defined, <code>false</code> otherwise.

+     */

+    public boolean isInvocationDefined( int index )

+    {

+        for ( InvocationProperty prop : InvocationProperty.values() )

+        {

+            if ( properties.getProperty( prop.toString() + '.' + index ) != null )

+            {

+                return true;

+            }

+        }

+        return false;

+    }

+    

+    /**

+     * Determines whether these invoker properties contain a build definition for the specified selector index.

+     * 

+     * @param index the index

+     * @return <code>true</code> if the selector with the specified index is defined, <code>false</code> otherwise.

+     * @since 3.0.0

+     */

+    public boolean isSelectorDefined( int index )

+    {

+        for ( SelectorProperty prop : SelectorProperty.values() )

+        {

+            if ( properties.getProperty( SELECTOR_PREFIX + index + prop.suffix ) != null )

+            {

+                return true;

+            }

+        }

+        return false;

+    }

+

+    /**

+     * Configures the specified invocation request from these invoker properties. Settings not present in the invoker

+     * properties will be left unchanged in the invocation request.

+     *

+     * @param request The invocation request to configure, must not be <code>null</code>.

+     * @param index The one-based index of the invocation to configure, must not be negative.

+     */

+    public void configureInvocation( InvocationRequest request, int index )

+    {

+        String project = get( InvocationProperty.PROJECT, index );

+        if ( project != null )

+        {

+            File file = new File( request.getBaseDirectory(), project );

+            if ( file.isFile() )

+            {

+                request.setBaseDirectory( file.getParentFile() );

+                request.setPomFile( file );

+            }

+            else

+            {

+                request.setBaseDirectory( file );

+                request.setPomFile( null );

+            }

+        }

+

+        String goals = get( InvocationProperty.GOALS, index );

+        if ( goals != null )

+        {

+            request.setGoals( new ArrayList<String>( Arrays.asList( StringUtils.split( goals, ", \t\n\r\f" ) ) ) );

+        }

+

+        String profiles = get( InvocationProperty.PROFILES, index );

+        if ( profiles != null )

+        {

+            // CHECKSTYLE_OFF: LineLength

+            request.setProfiles( new ArrayList<String>( Arrays.asList( StringUtils.split( profiles,

+                                                                                          ", \t\n\r\f" ) ) ) );

+            // CHECKSTYLE_ON: LineLength

+        }

+

+        String mvnOpts = get( InvocationProperty.MAVEN_OPTS, index );

+        if ( mvnOpts != null )

+        {

+            request.setMavenOpts( mvnOpts );

+        }

+

+        String failureBehavior = get( InvocationProperty.FAILURE_BEHAVIOR, index );

+        if ( failureBehavior != null )

+        {

+            ReactorFailureBehavior valueOf =

+                InvocationRequest.ReactorFailureBehavior.valueOfByLongOption( failureBehavior );

+            request.setReactorFailureBehavior( valueOf );

+        }

+

+        String nonRecursive = get( InvocationProperty.NON_RECURSIVE, index );

+        if ( nonRecursive != null )

+        {

+            request.setRecursive( !Boolean.valueOf( nonRecursive ) );

+        }

+

+        String offline = get( InvocationProperty.OFFLINE, index );

+        if ( offline != null )

+        {

+            request.setOffline( Boolean.valueOf( offline ) );

+        }

+

+        String debug = get( InvocationProperty.DEBUG, index );

+        if ( debug != null )

+        {

+            request.setDebug( Boolean.valueOf( debug ) );

+        }

+    }

+

+    /**

+     * Checks whether the specified exit code matches the one expected for the given invocation.

+     *

+     * @param exitCode The exit code of the Maven invocation to check.

+     * @param index The index of the invocation for which to check the exit code, must not be negative.

+     * @return <code>true</code> if the exit code is zero and a success was expected or if the exit code is non-zero and

+     *         a failue was expected, <code>false</code> otherwise.

+     */

+    public boolean isExpectedResult( int exitCode, int index )

+    {

+        boolean nonZeroExit = "failure".equalsIgnoreCase( get( "invoker.buildResult", index ) );

+        return ( exitCode != 0 ) == nonZeroExit;

+    }

+

+    /**

+     * Gets the path to the properties file used to set the system properties for the specified invocation.

+     *

+     * @param index The index of the invocation for which to check the exit code, must not be negative.

+     * @return The path to the properties file or <code>null</code> if not set.

+     */

+    public String getSystemPropertiesFile( int index )

+    {

+        return get( InvocationProperty.SYSTEM_PROPERTIES_FILE, index );

+    }

+

+    /**

+     * Gets a value from the invoker properties. The invoker properties are intended to describe the invocation settings

+     * for multiple builds of the same project. For this reason, the properties are indexed. First, a property named

+     * <code>key.index</code> will be queried. If this property does not exist, the value of the property named

+     * <code>key</code> will finally be returned.

+     *

+     * @param key The (base) key for the invoker property to lookup, must not be <code>null</code>.

+     * @param index The index of the invocation for which to retrieve the value, must not be negative.

+     * @return The value for the requested invoker property or <code>null</code> if not defined.

+     */

+    String get( String key, int index )

+    {

+        if ( index < 0 )

+        {

+            throw new IllegalArgumentException( "invalid invocation index: " + index );

+        }

+

+        String value = properties.getProperty( key + '.' + index );

+        if ( value == null )

+        {

+            value = properties.getProperty( key );

+        }

+        return value;

+    }

+

+    private String get( InvocationProperty prop, int index )

+    {

+        return get( prop.toString(), index );

+    }

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/InvokerReport.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerReport.java
similarity index 98%
rename from src/main/java/org/apache/maven/plugin/invoker/InvokerReport.java
rename to src/main/java/org/apache/maven/plugins/invoker/InvokerReport.java
index 7792974..95caf97 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/InvokerReport.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerReport.java
@@ -1,357 +1,357 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.IOException;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.NumberFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-import org.apache.maven.doxia.sink.Sink;
-import org.apache.maven.doxia.siterenderer.Renderer;
-import org.apache.maven.plugin.invoker.model.BuildJob;
-import org.apache.maven.plugin.invoker.model.io.xpp3.BuildJobXpp3Reader;
-import org.apache.maven.plugins.annotations.Component;
-import org.apache.maven.plugins.annotations.Mojo;
-import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.reporting.AbstractMavenReport;
-import org.apache.maven.reporting.MavenReportException;
-import org.codehaus.plexus.i18n.I18N;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-/**
- * Generate a report based on the results of the Maven invocations. <strong>Note:</strong> This mojo doesn't fork any
- * lifecycle, if you have a clean working copy, you have to use a command like
- * <code>mvn clean integration-test site</code> to ensure the build results are present when this goal is invoked.
- *
- * @author Olivier Lamy
- * @since 1.4
- */
-@Mojo( name = "report", threadSafe = true )
-public class InvokerReport
-    extends AbstractMavenReport
-{
-
-    /**
-     * The Maven Project.
-     */
-    @Parameter( defaultValue = "${project}", readonly = true, required = true )
-    protected MavenProject project;
-
-    /**
-     * Doxia Site Renderer component.
-     */
-    @Component
-    protected Renderer siteRenderer;
-
-    /**
-     * Internationalization component.
-     */
-    @Component
-    protected I18N i18n;
-
-    /**
-     * The output directory for the report. Note that this parameter is only evaluated if the goal is run directly from
-     * the command line. If the goal is run indirectly as part of a site generation, the output directory configured in
-     * the Maven Site Plugin is used instead.
-     */
-    @Parameter( defaultValue = "${project.reporting.outputDirectory}", required = true )
-    protected File outputDirectory;
-
-    /**
-     * Base directory where all build reports have been written to.
-     */
-    @Parameter( defaultValue = "${project.build.directory}/invoker-reports", property = "invoker.reportsDirectory" )
-    private File reportsDirectory;
-
-    /**
-     * The number format used to print percent values in the report locale.
-     */
-    private NumberFormat percentFormat;
-
-    /**
-     * The number format used to print time values in the report locale.
-     */
-    private NumberFormat secondsFormat;
-
-    protected void executeReport( Locale locale )
-        throws MavenReportException
-    {
-        DecimalFormatSymbols symbols = new DecimalFormatSymbols( locale );
-        percentFormat = new DecimalFormat( getText( locale, "report.invoker.format.percent" ), symbols );
-        secondsFormat = new DecimalFormat( getText( locale, "report.invoker.format.seconds" ), symbols );
-
-        Sink sink = getSink();
-
-        sink.head();
-
-        sink.title();
-        sink.text( getText( locale, "report.invoker.result.title" ) );
-        sink.title_();
-
-        sink.head_();
-
-        sink.body();
-
-        sink.section1();
-        sink.sectionTitle1();
-        sink.text( getText( locale, "report.invoker.result.title" ) );
-        sink.sectionTitle1_();
-        sink.paragraph();
-        sink.text( getText( locale, "report.invoker.result.description" ) );
-        sink.paragraph_();
-        sink.section1_();
-
-        // ----------------------------------
-        // build buildJob beans
-        // ----------------------------------
-        File[] reportFiles = ReportUtils.getReportFiles( reportsDirectory );
-        if ( reportFiles.length <= 0 )
-        {
-            getLog().info( "no invoker report files found, skip report generation" );
-            return;
-        }
-
-        List<BuildJob> buildJobs = new ArrayList<BuildJob>( reportFiles.length );
-        for ( File reportFile : reportFiles )
-        {
-            try
-            {
-                BuildJobXpp3Reader reader = new BuildJobXpp3Reader();
-                buildJobs.add( reader.read( ReaderFactory.newXmlReader( reportFile ) ) );
-            }
-            catch ( XmlPullParserException e )
-            {
-                throw new MavenReportException( "Failed to parse report file: " + reportFile, e );
-            }
-            catch ( IOException e )
-            {
-                throw new MavenReportException( "Failed to read report file: " + reportFile, e );
-            }
-        }
-
-        // ----------------------------------
-        // summary
-        // ----------------------------------
-
-        constructSummarySection( buildJobs, locale );
-
-        // ----------------------------------
-        // per file/it detail
-        // ----------------------------------
-
-        sink.section2();
-        sink.sectionTitle2();
-
-        sink.text( getText( locale, "report.invoker.detail.title" ) );
-
-        sink.sectionTitle2_();
-
-        sink.section2_();
-
-        // detail tests table header
-        sink.table();
-
-        sink.tableRow();
-        // -------------------------------------------
-        // name | Result | time | message
-        // -------------------------------------------
-        sinkTableHeader( sink, getText( locale, "report.invoker.detail.name" ) );
-        sinkTableHeader( sink, getText( locale, "report.invoker.detail.result" ) );
-        sinkTableHeader( sink, getText( locale, "report.invoker.detail.time" ) );
-        sinkTableHeader( sink, getText( locale, "report.invoker.detail.message" ) );
-
-        sink.tableRow_();
-
-        for ( BuildJob buildJob : buildJobs )
-        {
-            renderBuildJob( buildJob, locale );
-        }
-
-        sink.table_();
-
-        sink.body_();
-
-        sink.flush();
-        sink.close();
-    }
-
-    private void constructSummarySection( List<? extends BuildJob> buildJobs, Locale locale )
-    {
-        Sink sink = getSink();
-
-        sink.section2();
-        sink.sectionTitle2();
-
-        sink.text( getText( locale, "report.invoker.summary.title" ) );
-
-        sink.sectionTitle2_();
-        sink.section2_();
-
-        // ------------------------------------------------------------------------
-        // Building a table with
-        // it number | succes nb | failed nb | Success rate | total time | avg time
-        // ------------------------------------------------------------------------
-
-        sink.table();
-        sink.tableRow();
-
-        sinkTableHeader( sink, getText( locale, "report.invoker.summary.number" ) );
-        sinkTableHeader( sink, getText( locale, "report.invoker.summary.success" ) );
-        sinkTableHeader( sink, getText( locale, "report.invoker.summary.failed" ) );
-        sinkTableHeader( sink, getText( locale, "report.invoker.summary.skipped" ) );
-        sinkTableHeader( sink, getText( locale, "report.invoker.summary.success.rate" ) );
-        sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.total" ) );
-        sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.avg" ) );
-
-        int number = buildJobs.size();
-        int success = 0;
-        int failed = 0;
-        int skipped = 0;
-        double totalTime = 0;
-
-        for ( BuildJob buildJob : buildJobs )
-        {
-            if ( BuildJob.Result.SUCCESS.equals( buildJob.getResult() ) )
-            {
-                success++;
-            }
-            else if ( BuildJob.Result.SKIPPED.equals( buildJob.getResult() ) )
-            {
-                skipped++;
-            }
-            else
-            {
-                failed++;
-            }
-            totalTime += buildJob.getTime();
-        }
-
-        sink.tableRow_();
-        sink.tableRow();
-
-        sinkCell( sink, Integer.toString( number ) );
-        sinkCell( sink, Integer.toString( success ) );
-        sinkCell( sink, Integer.toString( failed ) );
-        sinkCell( sink, Integer.toString( skipped ) );
-
-        if ( success + failed > 0 )
-        {
-            sinkCell( sink, percentFormat.format( (double) success / ( success + failed ) ) );
-        }
-        else
-        {
-            sinkCell( sink, "" );
-        }
-
-        sinkCell( sink, secondsFormat.format( totalTime ) );
-
-        sinkCell( sink, secondsFormat.format( totalTime / number ) );
-
-        sink.tableRow_();
-        sink.table_();
-
-    }
-
-    private void renderBuildJob( BuildJob buildJob, Locale locale )
-    {
-        Sink sink = getSink();
-        sink.tableRow();
-        StringBuilder buffer = new StringBuilder();
-        if ( !StringUtils.isEmpty( buildJob.getName() ) && !StringUtils.isEmpty( buildJob.getDescription() ) )
-        {
-            buffer.append( buildJob.getName() );
-            buffer.append( " : " );
-            buffer.append( buildJob.getDescription() );
-        }
-        else
-        {
-            buffer.append( buildJob.getProject() );
-        }
-        sinkCell( sink, buffer.toString() );
-        // FIXME image
-        sinkCell( sink, buildJob.getResult() );
-        sinkCell( sink, secondsFormat.format( buildJob.getTime() ) );
-        sinkCell( sink, buildJob.getFailureMessage() );
-        sink.tableRow_();
-    }
-
-    protected String getOutputDirectory()
-    {
-        return outputDirectory.getAbsolutePath();
-    }
-
-    protected MavenProject getProject()
-    {
-        return project;
-    }
-
-    protected Renderer getSiteRenderer()
-    {
-        return siteRenderer;
-    }
-
-    public String getDescription( Locale locale )
-    {
-        return getText( locale, "report.invoker.result.description" );
-    }
-
-    public String getName( Locale locale )
-    {
-        return getText( locale, "report.invoker.result.name" );
-    }
-
-    public String getOutputName()
-    {
-        return "invoker-report";
-    }
-
-    public boolean canGenerateReport()
-    {
-        return ReportUtils.getReportFiles( reportsDirectory ).length > 0;
-    }
-
-    private String getText( Locale locale, String key )
-    {
-        return i18n.getString( "invoker-report", locale, key );
-    }
-
-    private void sinkTableHeader( Sink sink, String header )
-    {
-        sink.tableHeaderCell();
-        sink.text( header );
-        sink.tableHeaderCell_();
-    }
-
-    private void sinkCell( Sink sink, String text )
-    {
-        sink.tableCell();
-        sink.text( text );
-        sink.tableCell_();
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.IOException;

+import java.text.DecimalFormat;

+import java.text.DecimalFormatSymbols;

+import java.text.NumberFormat;

+import java.util.ArrayList;

+import java.util.List;

+import java.util.Locale;

+

+import org.apache.maven.doxia.sink.Sink;

+import org.apache.maven.doxia.siterenderer.Renderer;

+import org.apache.maven.plugins.invoker.model.BuildJob;

+import org.apache.maven.plugins.invoker.model.io.xpp3.BuildJobXpp3Reader;

+import org.apache.maven.plugins.annotations.Component;

+import org.apache.maven.plugins.annotations.Mojo;

+import org.apache.maven.plugins.annotations.Parameter;

+import org.apache.maven.project.MavenProject;

+import org.apache.maven.reporting.AbstractMavenReport;

+import org.apache.maven.reporting.MavenReportException;

+import org.codehaus.plexus.i18n.I18N;

+import org.codehaus.plexus.util.ReaderFactory;

+import org.codehaus.plexus.util.StringUtils;

+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

+

+/**

+ * Generate a report based on the results of the Maven invocations. <strong>Note:</strong> This mojo doesn't fork any

+ * lifecycle, if you have a clean working copy, you have to use a command like

+ * <code>mvn clean integration-test site</code> to ensure the build results are present when this goal is invoked.

+ *

+ * @author Olivier Lamy

+ * @since 1.4

+ */

+@Mojo( name = "report", threadSafe = true )

+public class InvokerReport

+    extends AbstractMavenReport

+{

+

+    /**

+     * The Maven Project.

+     */

+    @Parameter( defaultValue = "${project}", readonly = true, required = true )

+    protected MavenProject project;

+

+    /**

+     * Doxia Site Renderer component.

+     */

+    @Component

+    protected Renderer siteRenderer;

+

+    /**

+     * Internationalization component.

+     */

+    @Component

+    protected I18N i18n;

+

+    /**

+     * The output directory for the report. Note that this parameter is only evaluated if the goal is run directly from

+     * the command line. If the goal is run indirectly as part of a site generation, the output directory configured in

+     * the Maven Site Plugin is used instead.

+     */

+    @Parameter( defaultValue = "${project.reporting.outputDirectory}", required = true )

+    protected File outputDirectory;

+

+    /**

+     * Base directory where all build reports have been written to.

+     */

+    @Parameter( defaultValue = "${project.build.directory}/invoker-reports", property = "invoker.reportsDirectory" )

+    private File reportsDirectory;

+

+    /**

+     * The number format used to print percent values in the report locale.

+     */

+    private NumberFormat percentFormat;

+

+    /**

+     * The number format used to print time values in the report locale.

+     */

+    private NumberFormat secondsFormat;

+

+    protected void executeReport( Locale locale )

+        throws MavenReportException

+    {

+        DecimalFormatSymbols symbols = new DecimalFormatSymbols( locale );

+        percentFormat = new DecimalFormat( getText( locale, "report.invoker.format.percent" ), symbols );

+        secondsFormat = new DecimalFormat( getText( locale, "report.invoker.format.seconds" ), symbols );

+

+        Sink sink = getSink();

+

+        sink.head();

+

+        sink.title();

+        sink.text( getText( locale, "report.invoker.result.title" ) );

+        sink.title_();

+

+        sink.head_();

+

+        sink.body();

+

+        sink.section1();

+        sink.sectionTitle1();

+        sink.text( getText( locale, "report.invoker.result.title" ) );

+        sink.sectionTitle1_();

+        sink.paragraph();

+        sink.text( getText( locale, "report.invoker.result.description" ) );

+        sink.paragraph_();

+        sink.section1_();

+

+        // ----------------------------------

+        // build buildJob beans

+        // ----------------------------------

+        File[] reportFiles = ReportUtils.getReportFiles( reportsDirectory );

+        if ( reportFiles.length <= 0 )

+        {

+            getLog().info( "no invoker report files found, skip report generation" );

+            return;

+        }

+

+        List<BuildJob> buildJobs = new ArrayList<BuildJob>( reportFiles.length );

+        for ( File reportFile : reportFiles )

+        {

+            try

+            {

+                BuildJobXpp3Reader reader = new BuildJobXpp3Reader();

+                buildJobs.add( reader.read( ReaderFactory.newXmlReader( reportFile ) ) );

+            }

+            catch ( XmlPullParserException e )

+            {

+                throw new MavenReportException( "Failed to parse report file: " + reportFile, e );

+            }

+            catch ( IOException e )

+            {

+                throw new MavenReportException( "Failed to read report file: " + reportFile, e );

+            }

+        }

+

+        // ----------------------------------

+        // summary

+        // ----------------------------------

+

+        constructSummarySection( buildJobs, locale );

+

+        // ----------------------------------

+        // per file/it detail

+        // ----------------------------------

+

+        sink.section2();

+        sink.sectionTitle2();

+

+        sink.text( getText( locale, "report.invoker.detail.title" ) );

+

+        sink.sectionTitle2_();

+

+        sink.section2_();

+

+        // detail tests table header

+        sink.table();

+

+        sink.tableRow();

+        // -------------------------------------------

+        // name | Result | time | message

+        // -------------------------------------------

+        sinkTableHeader( sink, getText( locale, "report.invoker.detail.name" ) );

+        sinkTableHeader( sink, getText( locale, "report.invoker.detail.result" ) );

+        sinkTableHeader( sink, getText( locale, "report.invoker.detail.time" ) );

+        sinkTableHeader( sink, getText( locale, "report.invoker.detail.message" ) );

+

+        sink.tableRow_();

+

+        for ( BuildJob buildJob : buildJobs )

+        {

+            renderBuildJob( buildJob, locale );

+        }

+

+        sink.table_();

+

+        sink.body_();

+

+        sink.flush();

+        sink.close();

+    }

+

+    private void constructSummarySection( List<? extends BuildJob> buildJobs, Locale locale )

+    {

+        Sink sink = getSink();

+

+        sink.section2();

+        sink.sectionTitle2();

+

+        sink.text( getText( locale, "report.invoker.summary.title" ) );

+

+        sink.sectionTitle2_();

+        sink.section2_();

+

+        // ------------------------------------------------------------------------

+        // Building a table with

+        // it number | succes nb | failed nb | Success rate | total time | avg time

+        // ------------------------------------------------------------------------

+

+        sink.table();

+        sink.tableRow();

+

+        sinkTableHeader( sink, getText( locale, "report.invoker.summary.number" ) );

+        sinkTableHeader( sink, getText( locale, "report.invoker.summary.success" ) );

+        sinkTableHeader( sink, getText( locale, "report.invoker.summary.failed" ) );

+        sinkTableHeader( sink, getText( locale, "report.invoker.summary.skipped" ) );

+        sinkTableHeader( sink, getText( locale, "report.invoker.summary.success.rate" ) );

+        sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.total" ) );

+        sinkTableHeader( sink, getText( locale, "report.invoker.summary.time.avg" ) );

+

+        int number = buildJobs.size();

+        int success = 0;

+        int failed = 0;

+        int skipped = 0;

+        double totalTime = 0;

+

+        for ( BuildJob buildJob : buildJobs )

+        {

+            if ( BuildJob.Result.SUCCESS.equals( buildJob.getResult() ) )

+            {

+                success++;

+            }

+            else if ( BuildJob.Result.SKIPPED.equals( buildJob.getResult() ) )

+            {

+                skipped++;

+            }

+            else

+            {

+                failed++;

+            }

+            totalTime += buildJob.getTime();

+        }

+

+        sink.tableRow_();

+        sink.tableRow();

+

+        sinkCell( sink, Integer.toString( number ) );

+        sinkCell( sink, Integer.toString( success ) );

+        sinkCell( sink, Integer.toString( failed ) );

+        sinkCell( sink, Integer.toString( skipped ) );

+

+        if ( success + failed > 0 )

+        {

+            sinkCell( sink, percentFormat.format( (double) success / ( success + failed ) ) );

+        }

+        else

+        {

+            sinkCell( sink, "" );

+        }

+

+        sinkCell( sink, secondsFormat.format( totalTime ) );

+

+        sinkCell( sink, secondsFormat.format( totalTime / number ) );

+

+        sink.tableRow_();

+        sink.table_();

+

+    }

+

+    private void renderBuildJob( BuildJob buildJob, Locale locale )

+    {

+        Sink sink = getSink();

+        sink.tableRow();

+        StringBuilder buffer = new StringBuilder();

+        if ( !StringUtils.isEmpty( buildJob.getName() ) && !StringUtils.isEmpty( buildJob.getDescription() ) )

+        {

+            buffer.append( buildJob.getName() );

+            buffer.append( " : " );

+            buffer.append( buildJob.getDescription() );

+        }

+        else

+        {

+            buffer.append( buildJob.getProject() );

+        }

+        sinkCell( sink, buffer.toString() );

+        // FIXME image

+        sinkCell( sink, buildJob.getResult() );

+        sinkCell( sink, secondsFormat.format( buildJob.getTime() ) );

+        sinkCell( sink, buildJob.getFailureMessage() );

+        sink.tableRow_();

+    }

+

+    protected String getOutputDirectory()

+    {

+        return outputDirectory.getAbsolutePath();

+    }

+

+    protected MavenProject getProject()

+    {

+        return project;

+    }

+

+    protected Renderer getSiteRenderer()

+    {

+        return siteRenderer;

+    }

+

+    public String getDescription( Locale locale )

+    {

+        return getText( locale, "report.invoker.result.description" );

+    }

+

+    public String getName( Locale locale )

+    {

+        return getText( locale, "report.invoker.result.name" );

+    }

+

+    public String getOutputName()

+    {

+        return "invoker-report";

+    }

+

+    public boolean canGenerateReport()

+    {

+        return ReportUtils.getReportFiles( reportsDirectory ).length > 0;

+    }

+

+    private String getText( Locale locale, String key )

+    {

+        return i18n.getString( "invoker-report", locale, key );

+    }

+

+    private void sinkTableHeader( Sink sink, String header )

+    {

+        sink.tableHeaderCell();

+        sink.text( header );

+        sink.tableHeaderCell_();

+    }

+

+    private void sinkCell( Sink sink, String text )

+    {

+        sink.tableCell();

+        sink.text( text );

+        sink.tableCell_();

+    }

+

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/InvokerSession.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java
similarity index 98%
rename from src/main/java/org/apache/maven/plugin/invoker/InvokerSession.java
rename to src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java
index de95329..aa617da 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/InvokerSession.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java
@@ -1,279 +1,279 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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 static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.invoker.model.BuildJob;
-import org.apache.maven.plugin.logging.Log;
-
-/**
- * Tracks a set of build jobs and their results.
- *
- * @author Benjamin Bentmann
- */
-class InvokerSession
-{
-
-    private List<BuildJob> buildJobs;
-
-    private List<BuildJob> failedJobs;
-
-    private List<BuildJob> errorJobs;
-
-    private List<BuildJob> successfulJobs;
-
-    private List<BuildJob> skippedJobs;
-
-    /**
-     * Creates a new empty session.
-     */
-    public InvokerSession()
-    {
-        buildJobs = new ArrayList<BuildJob>();
-    }
-
-    /**
-     * Creates a session that initially contains the specified build jobs.
-     *
-     * @param buildJobs The build jobs to set, must not be <code>null</code>.
-     */
-    public InvokerSession( BuildJob[] buildJobs )
-    {
-        this.buildJobs = new ArrayList<BuildJob>( Arrays.asList( buildJobs ) );
-    }
-
-    /**
-     * Adds the specified build job to this session.
-     *
-     * @param buildJob The build job to add, must not be <code>null</code>.
-     */
-    public void addJob( BuildJob buildJob )
-    {
-        buildJobs.add( buildJob );
-
-        resetStats();
-    }
-
-    /**
-     * Sets the build jobs of this session.
-     *
-     * @param buildJobs The build jobs to set, must not be <code>null</code>.
-     */
-    public void setJobs( List<? extends BuildJob> buildJobs )
-    {
-        this.buildJobs = new ArrayList<BuildJob>( buildJobs );
-
-        resetStats();
-    }
-
-    /**
-     * Gets the build jobs in this session.
-     *
-     * @return The build jobs in this session, can be empty but never <code>null</code>.
-     */
-    public List<BuildJob> getJobs()
-    {
-        return buildJobs;
-    }
-
-    /**
-     * Gets the successful build jobs in this session.
-     *
-     * @return The successful build jobs in this session, can be empty but never <code>null</code>.
-     */
-    public List<BuildJob> getSuccessfulJobs()
-    {
-        updateStats();
-
-        return successfulJobs;
-    }
-
-    /**
-     * Gets the failed build jobs in this session.
-     *
-     * @return The failed build jobs in this session, can be empty but never <code>null</code>.
-     */
-    public List<BuildJob> getFailedJobs()
-    {
-        updateStats();
-
-        return failedJobs;
-    }
-
-    /**
-     * Gets the build jobs which had errors for this session.
-     *
-     * @return The build jobs in error for this session, can be empty but never <code>null</code>.
-     */
-    public List<BuildJob> getErrorJobs()
-    {
-        updateStats();
-
-        return errorJobs;
-    }
-
-    /**
-     * Gets the skipped build jobs in this session.
-     *
-     * @return The skipped build jobs in this session, can be empty but never <code>null</code>.
-     */
-    public List<BuildJob> getSkippedJobs()
-    {
-        updateStats();
-
-        return skippedJobs;
-    }
-
-    private void resetStats()
-    {
-        successfulJobs = null;
-        failedJobs = null;
-        skippedJobs = null;
-        errorJobs = null;
-    }
-
-    private void updateStats()
-    {
-        if ( successfulJobs != null && skippedJobs != null && failedJobs != null && errorJobs != null )
-        {
-            return;
-        }
-
-        successfulJobs = new ArrayList<BuildJob>();
-        failedJobs = new ArrayList<BuildJob>();
-        skippedJobs = new ArrayList<BuildJob>();
-        errorJobs = new ArrayList<BuildJob>();
-
-        for ( BuildJob buildJob : buildJobs )
-        {
-            if ( BuildJob.Result.SUCCESS.equals( buildJob.getResult() ) )
-            {
-                successfulJobs.add( buildJob );
-            }
-            else if ( BuildJob.Result.SKIPPED.equals( buildJob.getResult() ) )
-            {
-                skippedJobs.add( buildJob );
-            }
-            else if ( BuildJob.Result.ERROR.equals( buildJob.getResult() ) )
-            {
-                errorJobs.add( buildJob );
-            }
-            else if ( buildJob.getResult() != null )
-            {
-                failedJobs.add( buildJob );
-            }
-        }
-    }
-
-    /**
-     * Prints a summary of this session to the specified logger.
-     *
-     * @param logger The mojo logger to output messages to, must not be <code>null</code>.
-     * @param ignoreFailures A flag whether failures should be ignored or whether a build failure should be signaled.
-     */
-    public void logSummary( Log logger, boolean ignoreFailures )
-    {
-        updateStats();
-
-        String separator = buffer().strong( "-------------------------------------------------" ).toString();
-
-        logger.info( separator );
-        logger.info( "Build Summary:" );
-        logger.info( "  Passed: " + successfulJobs.size() + ", Failed: " + failedJobs.size() + ", Errors: "
-            + errorJobs.size() + ", Skipped: " + skippedJobs.size() );
-        logger.info( separator );
-
-        if ( !failedJobs.isEmpty() )
-        {
-            String heading = "The following builds failed:";
-            if ( ignoreFailures )
-            {
-                logger.warn( heading );
-            }
-            else
-            {
-                logger.error( heading );
-            }
-
-            for ( BuildJob buildJob : failedJobs )
-            {
-                String item = "*  " + buildJob.getProject();
-                if ( ignoreFailures )
-                {
-                    logger.warn( item );
-                }
-                else
-                {
-                    logger.error( item );
-                }
-            }
-
-            logger.info( separator );
-        }
-    }
-
-    /**
-     * Handles the build failures in this session.
-     *
-     * @param logger The mojo logger to output messages to, must not be <code>null</code>.
-     * @param ignoreFailures A flag whether failures should be ignored or whether a build failure should be signaled.
-     * @throws MojoFailureException If failures are present and not ignored.
-     */
-    public void handleFailures( Log logger, boolean ignoreFailures )
-        throws MojoFailureException
-    {
-        updateStats();
-
-        if ( !failedJobs.isEmpty() )
-        {
-            String message = failedJobs.size() + " build" + ( failedJobs.size() == 1 ? "" : "s" ) + " failed.";
-
-            if ( ignoreFailures )
-            {
-                logger.warn( "Ignoring that " + message );
-            }
-            else
-            {
-                throw new MojoFailureException( message + " See console output above for details." );
-            }
-        }
-
-        if ( !errorJobs.isEmpty() )
-        {
-            String message = errorJobs.size() + " build" + ( errorJobs.size() == 1 ? "" : "s" ) + " in error.";
-
-            if ( ignoreFailures )
-            {
-                logger.warn( "Ignoring that " + message );
-            }
-            else
-            {
-                throw new MojoFailureException( message + " See console output above for details." );
-            }
-        }
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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 static org.apache.maven.shared.utils.logging.MessageUtils.buffer;

+

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.List;

+

+import org.apache.maven.plugin.MojoFailureException;

+import org.apache.maven.plugins.invoker.model.BuildJob;

+import org.apache.maven.plugin.logging.Log;

+

+/**

+ * Tracks a set of build jobs and their results.

+ *

+ * @author Benjamin Bentmann

+ */

+class InvokerSession

+{

+

+    private List<BuildJob> buildJobs;

+

+    private List<BuildJob> failedJobs;

+

+    private List<BuildJob> errorJobs;

+

+    private List<BuildJob> successfulJobs;

+

+    private List<BuildJob> skippedJobs;

+

+    /**

+     * Creates a new empty session.

+     */

+    public InvokerSession()

+    {

+        buildJobs = new ArrayList<BuildJob>();

+    }

+

+    /**

+     * Creates a session that initially contains the specified build jobs.

+     *

+     * @param buildJobs The build jobs to set, must not be <code>null</code>.

+     */

+    public InvokerSession( BuildJob[] buildJobs )

+    {

+        this.buildJobs = new ArrayList<BuildJob>( Arrays.asList( buildJobs ) );

+    }

+

+    /**

+     * Adds the specified build job to this session.

+     *

+     * @param buildJob The build job to add, must not be <code>null</code>.

+     */

+    public void addJob( BuildJob buildJob )

+    {

+        buildJobs.add( buildJob );

+

+        resetStats();

+    }

+

+    /**

+     * Sets the build jobs of this session.

+     *

+     * @param buildJobs The build jobs to set, must not be <code>null</code>.

+     */

+    public void setJobs( List<? extends BuildJob> buildJobs )

+    {

+        this.buildJobs = new ArrayList<BuildJob>( buildJobs );

+

+        resetStats();

+    }

+

+    /**

+     * Gets the build jobs in this session.

+     *

+     * @return The build jobs in this session, can be empty but never <code>null</code>.

+     */

+    public List<BuildJob> getJobs()

+    {

+        return buildJobs;

+    }

+

+    /**

+     * Gets the successful build jobs in this session.

+     *

+     * @return The successful build jobs in this session, can be empty but never <code>null</code>.

+     */

+    public List<BuildJob> getSuccessfulJobs()

+    {

+        updateStats();

+

+        return successfulJobs;

+    }

+

+    /**

+     * Gets the failed build jobs in this session.

+     *

+     * @return The failed build jobs in this session, can be empty but never <code>null</code>.

+     */

+    public List<BuildJob> getFailedJobs()

+    {

+        updateStats();

+

+        return failedJobs;

+    }

+

+    /**

+     * Gets the build jobs which had errors for this session.

+     *

+     * @return The build jobs in error for this session, can be empty but never <code>null</code>.

+     */

+    public List<BuildJob> getErrorJobs()

+    {

+        updateStats();

+

+        return errorJobs;

+    }

+

+    /**

+     * Gets the skipped build jobs in this session.

+     *

+     * @return The skipped build jobs in this session, can be empty but never <code>null</code>.

+     */

+    public List<BuildJob> getSkippedJobs()

+    {

+        updateStats();

+

+        return skippedJobs;

+    }

+

+    private void resetStats()

+    {

+        successfulJobs = null;

+        failedJobs = null;

+        skippedJobs = null;

+        errorJobs = null;

+    }

+

+    private void updateStats()

+    {

+        if ( successfulJobs != null && skippedJobs != null && failedJobs != null && errorJobs != null )

+        {

+            return;

+        }

+

+        successfulJobs = new ArrayList<BuildJob>();

+        failedJobs = new ArrayList<BuildJob>();

+        skippedJobs = new ArrayList<BuildJob>();

+        errorJobs = new ArrayList<BuildJob>();

+

+        for ( BuildJob buildJob : buildJobs )

+        {

+            if ( BuildJob.Result.SUCCESS.equals( buildJob.getResult() ) )

+            {

+                successfulJobs.add( buildJob );

+            }

+            else if ( BuildJob.Result.SKIPPED.equals( buildJob.getResult() ) )

+            {

+                skippedJobs.add( buildJob );

+            }

+            else if ( BuildJob.Result.ERROR.equals( buildJob.getResult() ) )

+            {

+                errorJobs.add( buildJob );

+            }

+            else if ( buildJob.getResult() != null )

+            {

+                failedJobs.add( buildJob );

+            }

+        }

+    }

+

+    /**

+     * Prints a summary of this session to the specified logger.

+     *

+     * @param logger The mojo logger to output messages to, must not be <code>null</code>.

+     * @param ignoreFailures A flag whether failures should be ignored or whether a build failure should be signaled.

+     */

+    public void logSummary( Log logger, boolean ignoreFailures )

+    {

+        updateStats();

+

+        String separator = buffer().strong( "-------------------------------------------------" ).toString();

+

+        logger.info( separator );

+        logger.info( "Build Summary:" );

+        logger.info( "  Passed: " + successfulJobs.size() + ", Failed: " + failedJobs.size() + ", Errors: "

+            + errorJobs.size() + ", Skipped: " + skippedJobs.size() );

+        logger.info( separator );

+

+        if ( !failedJobs.isEmpty() )

+        {

+            String heading = "The following builds failed:";

+            if ( ignoreFailures )

+            {

+                logger.warn( heading );

+            }

+            else

+            {

+                logger.error( heading );

+            }

+

+            for ( BuildJob buildJob : failedJobs )

+            {

+                String item = "*  " + buildJob.getProject();

+                if ( ignoreFailures )

+                {

+                    logger.warn( item );

+                }

+                else

+                {

+                    logger.error( item );

+                }

+            }

+

+            logger.info( separator );

+        }

+    }

+

+    /**

+     * Handles the build failures in this session.

+     *

+     * @param logger The mojo logger to output messages to, must not be <code>null</code>.

+     * @param ignoreFailures A flag whether failures should be ignored or whether a build failure should be signaled.

+     * @throws MojoFailureException If failures are present and not ignored.

+     */

+    public void handleFailures( Log logger, boolean ignoreFailures )

+        throws MojoFailureException

+    {

+        updateStats();

+

+        if ( !failedJobs.isEmpty() )

+        {

+            String message = failedJobs.size() + " build" + ( failedJobs.size() == 1 ? "" : "s" ) + " failed.";

+

+            if ( ignoreFailures )

+            {

+                logger.warn( "Ignoring that " + message );

+            }

+            else

+            {

+                throw new MojoFailureException( message + " See console output above for details." );

+            }

+        }

+

+        if ( !errorJobs.isEmpty() )

+        {

+            String message = errorJobs.size() + " build" + ( errorJobs.size() == 1 ? "" : "s" ) + " in error.";

+

+            if ( ignoreFailures )

+            {

+                logger.warn( "Ignoring that " + message );

+            }

+            else

+            {

+                throw new MojoFailureException( message + " See console output above for details." );

+            }

+        }

+    }

+

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/MetadataUtils.java b/src/main/java/org/apache/maven/plugins/invoker/MetadataUtils.java
similarity index 99%
rename from src/main/java/org/apache/maven/plugin/invoker/MetadataUtils.java
rename to src/main/java/org/apache/maven/plugins/invoker/MetadataUtils.java
index d353406..23ce866 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/MetadataUtils.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/MetadataUtils.java
@@ -1,186 +1,186 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.IOException;
-import java.io.Reader;
-import java.io.Writer;
-import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Date;
-import java.util.LinkedHashSet;
-import java.util.Set;
-import java.util.TimeZone;
-
-import org.apache.maven.artifact.Artifact;
-import org.codehaus.plexus.util.IOUtil;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.WriterFactory;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
-import org.codehaus.plexus.util.xml.Xpp3DomUtils;
-import org.codehaus.plexus.util.xml.Xpp3DomWriter;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-/**
- * Provides utility methods for artifact metadata processing.
- *
- * @author Benjamin Bentmann
- */
-class MetadataUtils
-{
-
-    /**
-     * Creates local metadata files for the specified artifact. The goal is to simulate the installation of the artifact
-     * by a local build, thereby decoupling the forked builds from the inderministic collection of remote repositories
-     * that are available to the main build and from which the artifact was originally resolved.
-     *
-     * @param file The artifact's file in the local test repository, must not be <code>null</code>.
-     * @param artifact The artifact to create metadata for, must not be <code>null</code>.
-     * @throws IOException If the metadata could not be created.
-     */
-    public static void createMetadata( File file, Artifact artifact )
-        throws IOException
-    {
-        TimeZone tz = java.util.TimeZone.getTimeZone( "UTC" );
-        SimpleDateFormat fmt = new SimpleDateFormat( "yyyyMMddHHmmss" );
-        fmt.setTimeZone( tz );
-        String timestamp = fmt.format( new Date() );
-
-        if ( artifact.isSnapshot() )
-        {
-            File metadataFile = new File( file.getParentFile(), "maven-metadata-local.xml" );
-
-            Xpp3Dom metadata = new Xpp3Dom( "metadata" );
-            addChild( metadata, "groupId", artifact.getGroupId() );
-            addChild( metadata, "artifactId", artifact.getArtifactId() );
-            addChild( metadata, "version", artifact.getBaseVersion() );
-            Xpp3Dom versioning = new Xpp3Dom( "versioning" );
-            versioning.addChild( addChild( new Xpp3Dom( "snapshot" ), "localCopy", "true" ) );
-            addChild( versioning, "lastUpdated", timestamp );
-            metadata.addChild( versioning );
-
-            writeMetadata( metadataFile, metadata );
-        }
-
-        File metadataFile = new File( file.getParentFile().getParentFile(), "maven-metadata-local.xml" );
-
-        Set<String> allVersions = new LinkedHashSet<String>();
-
-        Xpp3Dom metadata = readMetadata( metadataFile );
-
-        if ( metadata != null )
-        {
-            Xpp3Dom versioning = metadata.getChild( "versioning" );
-            if ( versioning != null )
-            {
-                Xpp3Dom versions = versioning.getChild( "versions" );
-                if ( versions != null )
-                {
-
-                    Xpp3Dom[] children = versions.getChildren( "version" );
-                    for ( Xpp3Dom aChildren : children )
-                    {
-                        allVersions.add( aChildren.getValue() );
-                    }
-                }
-            }
-        }
-
-        allVersions.add( artifact.getBaseVersion() );
-
-        metadata = new Xpp3Dom( "metadata" );
-        addChild( metadata, "groupId", artifact.getGroupId() );
-        addChild( metadata, "artifactId", artifact.getArtifactId() );
-        Xpp3Dom versioning = new Xpp3Dom( "versioning" );
-        versioning.addChild( addChildren( new Xpp3Dom( "versions" ), "version", allVersions ) );
-        addChild( versioning, "lastUpdated", timestamp );
-        metadata.addChild( versioning );
-
-        metadata = Xpp3DomUtils.mergeXpp3Dom( metadata, readMetadata( metadataFile ) );
-
-        writeMetadata( metadataFile, metadata );
-    }
-
-    private static Xpp3Dom addChild( Xpp3Dom parent, String childName, String childValue )
-    {
-        Xpp3Dom child = new Xpp3Dom( childName );
-        child.setValue( childValue );
-        parent.addChild( child );
-        return parent;
-    }
-
-    private static Xpp3Dom addChildren( Xpp3Dom parent, String childName, Collection<String> childValues )
-    {
-        for ( String childValue : childValues )
-        {
-            addChild( parent, childName, childValue );
-        }
-        return parent;
-    }
-
-    private static Xpp3Dom readMetadata( File metadataFile )
-        throws IOException
-    {
-        if ( !metadataFile.isFile() )
-        {
-            return null;
-        }
-
-        Reader reader = null;
-        try
-        {
-            reader = ReaderFactory.newXmlReader( metadataFile );
-            final Xpp3Dom xpp3Dom = Xpp3DomBuilder.build( reader );
-            reader.close();
-            reader = null;
-            return xpp3Dom;
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw (IOException) new IOException( e.getMessage() ).initCause( e );
-        }
-        finally
-        {
-            IOUtil.close( reader );
-        }
-    }
-
-    private static void writeMetadata( File metadataFile, Xpp3Dom metadata )
-        throws IOException
-    {
-        metadataFile.getParentFile().mkdirs();
-
-        Writer writer = null;
-        try
-        {
-            writer = WriterFactory.newXmlWriter( metadataFile );
-            Xpp3DomWriter.write( writer, metadata );
-            writer.close();
-            writer = null;
-        }
-        finally
-        {
-            IOUtil.close( writer );
-        }
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.IOException;

+import java.io.Reader;

+import java.io.Writer;

+import java.text.SimpleDateFormat;

+import java.util.Collection;

+import java.util.Date;

+import java.util.LinkedHashSet;

+import java.util.Set;

+import java.util.TimeZone;

+

+import org.apache.maven.artifact.Artifact;

+import org.codehaus.plexus.util.IOUtil;

+import org.codehaus.plexus.util.ReaderFactory;

+import org.codehaus.plexus.util.WriterFactory;

+import org.codehaus.plexus.util.xml.Xpp3Dom;

+import org.codehaus.plexus.util.xml.Xpp3DomBuilder;

+import org.codehaus.plexus.util.xml.Xpp3DomUtils;

+import org.codehaus.plexus.util.xml.Xpp3DomWriter;

+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

+

+/**

+ * Provides utility methods for artifact metadata processing.

+ *

+ * @author Benjamin Bentmann

+ */

+class MetadataUtils

+{

+

+    /**

+     * Creates local metadata files for the specified artifact. The goal is to simulate the installation of the artifact

+     * by a local build, thereby decoupling the forked builds from the inderministic collection of remote repositories

+     * that are available to the main build and from which the artifact was originally resolved.

+     *

+     * @param file The artifact's file in the local test repository, must not be <code>null</code>.

+     * @param artifact The artifact to create metadata for, must not be <code>null</code>.

+     * @throws IOException If the metadata could not be created.

+     */

+    public static void createMetadata( File file, Artifact artifact )

+        throws IOException

+    {

+        TimeZone tz = java.util.TimeZone.getTimeZone( "UTC" );

+        SimpleDateFormat fmt = new SimpleDateFormat( "yyyyMMddHHmmss" );

+        fmt.setTimeZone( tz );

+        String timestamp = fmt.format( new Date() );

+

+        if ( artifact.isSnapshot() )

+        {

+            File metadataFile = new File( file.getParentFile(), "maven-metadata-local.xml" );

+

+            Xpp3Dom metadata = new Xpp3Dom( "metadata" );

+            addChild( metadata, "groupId", artifact.getGroupId() );

+            addChild( metadata, "artifactId", artifact.getArtifactId() );

+            addChild( metadata, "version", artifact.getBaseVersion() );

+            Xpp3Dom versioning = new Xpp3Dom( "versioning" );

+            versioning.addChild( addChild( new Xpp3Dom( "snapshot" ), "localCopy", "true" ) );

+            addChild( versioning, "lastUpdated", timestamp );

+            metadata.addChild( versioning );

+

+            writeMetadata( metadataFile, metadata );

+        }

+

+        File metadataFile = new File( file.getParentFile().getParentFile(), "maven-metadata-local.xml" );

+

+        Set<String> allVersions = new LinkedHashSet<String>();

+

+        Xpp3Dom metadata = readMetadata( metadataFile );

+

+        if ( metadata != null )

+        {

+            Xpp3Dom versioning = metadata.getChild( "versioning" );

+            if ( versioning != null )

+            {

+                Xpp3Dom versions = versioning.getChild( "versions" );

+                if ( versions != null )

+                {

+

+                    Xpp3Dom[] children = versions.getChildren( "version" );

+                    for ( Xpp3Dom aChildren : children )

+                    {

+                        allVersions.add( aChildren.getValue() );

+                    }

+                }

+            }

+        }

+

+        allVersions.add( artifact.getBaseVersion() );

+

+        metadata = new Xpp3Dom( "metadata" );

+        addChild( metadata, "groupId", artifact.getGroupId() );

+        addChild( metadata, "artifactId", artifact.getArtifactId() );

+        Xpp3Dom versioning = new Xpp3Dom( "versioning" );

+        versioning.addChild( addChildren( new Xpp3Dom( "versions" ), "version", allVersions ) );

+        addChild( versioning, "lastUpdated", timestamp );

+        metadata.addChild( versioning );

+

+        metadata = Xpp3DomUtils.mergeXpp3Dom( metadata, readMetadata( metadataFile ) );

+

+        writeMetadata( metadataFile, metadata );

+    }

+

+    private static Xpp3Dom addChild( Xpp3Dom parent, String childName, String childValue )

+    {

+        Xpp3Dom child = new Xpp3Dom( childName );

+        child.setValue( childValue );

+        parent.addChild( child );

+        return parent;

+    }

+

+    private static Xpp3Dom addChildren( Xpp3Dom parent, String childName, Collection<String> childValues )

+    {

+        for ( String childValue : childValues )

+        {

+            addChild( parent, childName, childValue );

+        }

+        return parent;

+    }

+

+    private static Xpp3Dom readMetadata( File metadataFile )

+        throws IOException

+    {

+        if ( !metadataFile.isFile() )

+        {

+            return null;

+        }

+

+        Reader reader = null;

+        try

+        {

+            reader = ReaderFactory.newXmlReader( metadataFile );

+            final Xpp3Dom xpp3Dom = Xpp3DomBuilder.build( reader );

+            reader.close();

+            reader = null;

+            return xpp3Dom;

+        }

+        catch ( XmlPullParserException e )

+        {

+            throw (IOException) new IOException( e.getMessage() ).initCause( e );

+        }

+        finally

+        {

+            IOUtil.close( reader );

+        }

+    }

+

+    private static void writeMetadata( File metadataFile, Xpp3Dom metadata )

+        throws IOException

+    {

+        metadataFile.getParentFile().mkdirs();

+

+        Writer writer = null;

+        try

+        {

+            writer = WriterFactory.newXmlWriter( metadataFile );

+            Xpp3DomWriter.write( writer, metadata );

+            writer.close();

+            writer = null;

+        }

+        finally

+        {

+            IOUtil.close( writer );

+        }

+    }

+

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/PomUtils.java b/src/main/java/org/apache/maven/plugins/invoker/PomUtils.java
similarity index 97%
rename from src/main/java/org/apache/maven/plugin/invoker/PomUtils.java
rename to src/main/java/org/apache/maven/plugins/invoker/PomUtils.java
index 8aba3e9..5130947 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/PomUtils.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/PomUtils.java
@@ -1,74 +1,74 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.IOException;
-import java.io.Reader;
-
-import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.codehaus.plexus.util.IOUtil;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-/**
- * Provides utility methods for POM processing.
- *
- * @author Benjamin Bentmann
- */
-class PomUtils
-{
-
-    /**
-     * Loads the (raw) model from the specified POM file.
-     *
-     * @param pomFile The path to the POM file to load, must not be <code>null</code>.
-     * @return The raw model, never <code>null</code>.
-     * @throws MojoExecutionException If the POM file could not be loaded.
-     */
-    public static Model loadPom( File pomFile )
-        throws MojoExecutionException
-    {
-        Reader reader = null;
-        try
-        {
-            reader = ReaderFactory.newXmlReader( pomFile );
-            final Model model = new MavenXpp3Reader().read( reader, false );
-            reader.close();
-            reader = null;
-            return model;
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new MojoExecutionException( "Failed to parse POM: " + pomFile, e );
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( "Failed to read POM: " + pomFile, e );
-        }
-        finally
-        {
-            IOUtil.close( reader );
-        }
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.IOException;

+import java.io.Reader;

+

+import org.apache.maven.model.Model;

+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;

+import org.apache.maven.plugin.MojoExecutionException;

+import org.codehaus.plexus.util.IOUtil;

+import org.codehaus.plexus.util.ReaderFactory;

+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

+

+/**

+ * Provides utility methods for POM processing.

+ *

+ * @author Benjamin Bentmann

+ */

+class PomUtils

+{

+

+    /**

+     * Loads the (raw) model from the specified POM file.

+     *

+     * @param pomFile The path to the POM file to load, must not be <code>null</code>.

+     * @return The raw model, never <code>null</code>.

+     * @throws MojoExecutionException If the POM file could not be loaded.

+     */

+    public static Model loadPom( File pomFile )

+        throws MojoExecutionException

+    {

+        Reader reader = null;

+        try

+        {

+            reader = ReaderFactory.newXmlReader( pomFile );

+            final Model model = new MavenXpp3Reader().read( reader, false );

+            reader.close();

+            reader = null;

+            return model;

+        }

+        catch ( XmlPullParserException e )

+        {

+            throw new MojoExecutionException( "Failed to parse POM: " + pomFile, e );

+        }

+        catch ( IOException e )

+        {

+            throw new MojoExecutionException( "Failed to read POM: " + pomFile, e );

+        }

+        finally

+        {

+            IOUtil.close( reader );

+        }

+    }

+

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/ReportUtils.java b/src/main/java/org/apache/maven/plugins/invoker/ReportUtils.java
similarity index 97%
rename from src/main/java/org/apache/maven/plugin/invoker/ReportUtils.java
rename to src/main/java/org/apache/maven/plugins/invoker/ReportUtils.java
index 3a37072..9f4207c 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/ReportUtils.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/ReportUtils.java
@@ -1,63 +1,63 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.FilenameFilter;
-
-/**
- * Provides utility methods for invoker report processing.
- *
- * @author Benjamin Bentmann
- */
-class ReportUtils
-{
-
-    private static class FileFilterOnlyXmlFile
-        implements FilenameFilter
-    {
-
-        public boolean accept( File dir, String name )
-        {
-            return name.startsWith( "BUILD-" ) && name.endsWith( ".xml" );
-        }
-
-    }
-
-    /**
-     * Gets the paths to the invoker reports available in the specified directory.
-     *
-     * @param reportsDirectory The base directory where the invoker reports are located in, may be <code>null</code>.
-     * @return The paths to the invoker reports, can be empty but never <code>null</code>.
-     */
-    public static File[] getReportFiles( File reportsDirectory )
-    {
-        File[] reportFiles =
-            ( reportsDirectory != null ) ? reportsDirectory.listFiles( new FileFilterOnlyXmlFile() ) : null;
-
-        if ( reportFiles == null )
-        {
-            reportFiles = new File[0];
-        }
-
-        return reportFiles;
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.FilenameFilter;

+

+/**

+ * Provides utility methods for invoker report processing.

+ *

+ * @author Benjamin Bentmann

+ */

+class ReportUtils

+{

+

+    private static class FileFilterOnlyXmlFile

+        implements FilenameFilter

+    {

+

+        public boolean accept( File dir, String name )

+        {

+            return name.startsWith( "BUILD-" ) && name.endsWith( ".xml" );

+        }

+

+    }

+

+    /**

+     * Gets the paths to the invoker reports available in the specified directory.

+     *

+     * @param reportsDirectory The base directory where the invoker reports are located in, may be <code>null</code>.

+     * @return The paths to the invoker reports, can be empty but never <code>null</code>.

+     */

+    public static File[] getReportFiles( File reportsDirectory )

+    {

+        File[] reportFiles =

+            ( reportsDirectory != null ) ? reportsDirectory.listFiles( new FileFilterOnlyXmlFile() ) : null;

+

+        if ( reportFiles == null )

+        {

+            reportFiles = new File[0];

+        }

+

+        return reportFiles;

+    }

+

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/Selector.java b/src/main/java/org/apache/maven/plugins/invoker/Selector.java
similarity index 98%
rename from src/main/java/org/apache/maven/plugin/invoker/Selector.java
rename to src/main/java/org/apache/maven/plugins/invoker/Selector.java
index 102be42..d4fccc1 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/Selector.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/Selector.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.invoker;

+package org.apache.maven.plugins.invoker;

 

 /*

  * Licensed to the Apache Software Foundation (ASF) under one

diff --git a/src/main/java/org/apache/maven/plugin/invoker/SelectorUtils.java b/src/main/java/org/apache/maven/plugins/invoker/SelectorUtils.java
similarity index 99%
rename from src/main/java/org/apache/maven/plugin/invoker/SelectorUtils.java
rename to src/main/java/org/apache/maven/plugins/invoker/SelectorUtils.java
index d313280..5f18259 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/SelectorUtils.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/SelectorUtils.java
@@ -1,283 +1,283 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.FilenameFilter;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Properties;
-
-import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.Os;
-import org.codehaus.plexus.util.StringUtils;
-
-/**
- * Provides utility methods for selecting build jobs based on environmental conditions.
- *
- * @author Benjamin Bentmann
- */
-class SelectorUtils
-{
-
-    static void parseList( String list, Collection<String> includes, Collection<String> excludes )
-    {
-        String[] tokens = ( list != null ) ? StringUtils.split( list, "," ) : new String[0];
-
-        for ( String token1 : tokens )
-        {
-            String token = token1.trim();
-
-            if ( token.startsWith( "!" ) )
-            {
-                excludes.add( token.substring( 1 ) );
-            }
-            else
-            {
-                includes.add( token );
-            }
-        }
-    }
-
-    static boolean isOsFamily( String osSpec )
-    {
-        List<String> includes = new ArrayList<String>();
-        List<String> excludes = new ArrayList<String>();
-        parseList( osSpec, includes, excludes );
-
-        return isOsFamily( includes, true ) && !isOsFamily( excludes, false );
-    }
-
-    static boolean isOsFamily( List<String> families, boolean defaultMatch )
-    {
-        if ( families != null && !families.isEmpty() )
-        {
-            for ( String family : families )
-            {
-                if ( Os.isFamily( family ) )
-                {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-        else
-        {
-            return defaultMatch;
-        }
-    }
-
-    /**
-     * Retrieves the current Maven version.
-     *
-     * @return The current Maven version.
-     */
-    static String getMavenVersion()
-    {
-        try
-        {
-            // This relies on the fact that MavenProject is the in core classloader
-            // and that the core classloader is for the maven-core artifact
-            // and that should have a pom.properties file
-            // if this ever changes, we will have to revisit this code.
-            Properties properties = new Properties();
-            // CHECKSTYLE_OFF: LineLength
-            properties.load( MavenProject.class.getClassLoader().getResourceAsStream( "META-INF/maven/org.apache.maven/maven-core/pom.properties" ) );
-            // CHECKSTYLE_ON: LineLength
-            return StringUtils.trim( properties.getProperty( "version" ) );
-        }
-        catch ( Exception e )
-        {
-            return null;
-        }
-    }
-
-    static String getMavenVersion( File mavenHome )
-    {
-        File mavenLib = new File( mavenHome, "lib" );
-        File[] jarFiles = mavenLib.listFiles( new FilenameFilter()
-        {
-            public boolean accept( File dir, String name )
-            {
-                return name.endsWith( ".jar" );
-            }
-        } );
-
-        for ( File file : jarFiles )
-        {
-            try
-            {
-                @SuppressWarnings( "deprecation" )
-                URL url =
-                    new URL( "jar:" + file.toURL().toExternalForm()
-                        + "!/META-INF/maven/org.apache.maven/maven-core/pom.properties" );
-
-                Properties properties = new Properties();
-                properties.load( url.openStream() );
-                String version = StringUtils.trim( properties.getProperty( "version" ) );
-                if ( version != null )
-                {
-                    return version;
-                }
-            }
-            catch ( MalformedURLException e )
-            {
-                // ignore
-            }
-            catch ( IOException e )
-            {
-                // ignore
-            }
-        }
-        return null;
-    }
-
-    static boolean isMavenVersion( String mavenSpec )
-    {
-        return isMavenVersion( mavenSpec, getMavenVersion() );
-    }
-
-    static boolean isMavenVersion( String mavenSpec, String actualVersion )
-    {
-        List<String> includes = new ArrayList<String>();
-        List<String> excludes = new ArrayList<String>();
-        parseList( mavenSpec, includes, excludes );
-
-        List<Integer> mavenVersionList = parseVersion( actualVersion );
-
-        return isJreVersion( mavenVersionList, includes, true ) && !isJreVersion( mavenVersionList, excludes, false );
-    }
-
-    static String getJreVersion()
-    {
-        return System.getProperty( "java.version", "" );
-    }
-
-    static String getJreVersion( File javaHome )
-    {
-        // @todo detect actual version
-        return null;
-    }
-
-    static boolean isJreVersion( String jreSpec )
-    {
-        return isJreVersion( jreSpec, getJreVersion() );
-    }
-
-    static boolean isJreVersion( String jreSpec, String actualJreVersion )
-    {
-        List<String> includes = new ArrayList<String>();
-        List<String> excludes = new ArrayList<String>();
-        parseList( jreSpec, includes, excludes );
-
-        List<Integer> jreVersion = parseVersion( actualJreVersion );
-
-        return isJreVersion( jreVersion, includes, true ) && !isJreVersion( jreVersion, excludes, false );
-    }
-
-    static boolean isJreVersion( List<Integer> jreVersion, List<String> versionPatterns, boolean defaultMatch )
-    {
-        if ( versionPatterns != null && !versionPatterns.isEmpty() )
-        {
-            for ( String versionPattern : versionPatterns )
-            {
-                if ( isJreVersion( jreVersion, versionPattern ) )
-                {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-        else
-        {
-            return defaultMatch;
-        }
-    }
-
-    static boolean isJreVersion( List<Integer> jreVersion, String versionPattern )
-    {
-        List<Integer> checkVersion = parseVersion( versionPattern );
-
-        if ( versionPattern.endsWith( "+" ) )
-        {
-            // 1.5+ <=> [1.5,)
-            return compareVersions( jreVersion, checkVersion ) >= 0;
-        }
-        else if ( versionPattern.endsWith( "-" ) )
-        {
-            // 1.5- <=> (,1.5)
-            return compareVersions( jreVersion, checkVersion ) < 0;
-        }
-        else
-        {
-            // 1.5 <=> [1.5,1.6)
-            return checkVersion.size() <= jreVersion.size()
-                && checkVersion.equals( jreVersion.subList( 0, checkVersion.size() ) );
-        }
-    }
-
-    static List<Integer> parseVersion( String version )
-    {
-        version = version.replaceAll( "[^0-9]", "." );
-
-        String[] tokens = StringUtils.split( version, "." );
-
-        List<Integer> numbers = new ArrayList<Integer>();
-
-        for ( String token : tokens )
-        {
-            numbers.add( Integer.valueOf( token ) );
-        }
-
-        return numbers;
-    }
-
-    static int compareVersions( List<Integer> version1, List<Integer> version2 )
-    {
-        for ( Iterator<Integer> it1 = version1.iterator(), it2 = version2.iterator();; )
-        {
-            if ( !it1.hasNext() )
-            {
-                return it2.hasNext() ? -1 : 0;
-            }
-            if ( !it2.hasNext() )
-            {
-                return it1.hasNext() ? 1 : 0;
-            }
-
-            Integer num1 = it1.next();
-            Integer num2 = it2.next();
-
-            int rel = num1.compareTo( num2 );
-            if ( rel != 0 )
-            {
-                return rel;
-            }
-        }
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.FilenameFilter;

+import java.io.IOException;

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.util.ArrayList;

+import java.util.Collection;

+import java.util.Iterator;

+import java.util.List;

+import java.util.Properties;

+

+import org.apache.maven.project.MavenProject;

+import org.codehaus.plexus.util.Os;

+import org.codehaus.plexus.util.StringUtils;

+

+/**

+ * Provides utility methods for selecting build jobs based on environmental conditions.

+ *

+ * @author Benjamin Bentmann

+ */

+class SelectorUtils

+{

+

+    static void parseList( String list, Collection<String> includes, Collection<String> excludes )

+    {

+        String[] tokens = ( list != null ) ? StringUtils.split( list, "," ) : new String[0];

+

+        for ( String token1 : tokens )

+        {

+            String token = token1.trim();

+

+            if ( token.startsWith( "!" ) )

+            {

+                excludes.add( token.substring( 1 ) );

+            }

+            else

+            {

+                includes.add( token );

+            }

+        }

+    }

+

+    static boolean isOsFamily( String osSpec )

+    {

+        List<String> includes = new ArrayList<String>();

+        List<String> excludes = new ArrayList<String>();

+        parseList( osSpec, includes, excludes );

+

+        return isOsFamily( includes, true ) && !isOsFamily( excludes, false );

+    }

+

+    static boolean isOsFamily( List<String> families, boolean defaultMatch )

+    {

+        if ( families != null && !families.isEmpty() )

+        {

+            for ( String family : families )

+            {

+                if ( Os.isFamily( family ) )

+                {

+                    return true;

+                }

+            }

+

+            return false;

+        }

+        else

+        {

+            return defaultMatch;

+        }

+    }

+

+    /**

+     * Retrieves the current Maven version.

+     *

+     * @return The current Maven version.

+     */

+    static String getMavenVersion()

+    {

+        try

+        {

+            // This relies on the fact that MavenProject is the in core classloader

+            // and that the core classloader is for the maven-core artifact

+            // and that should have a pom.properties file

+            // if this ever changes, we will have to revisit this code.

+            Properties properties = new Properties();

+            // CHECKSTYLE_OFF: LineLength

+            properties.load( MavenProject.class.getClassLoader().getResourceAsStream( "META-INF/maven/org.apache.maven/maven-core/pom.properties" ) );

+            // CHECKSTYLE_ON: LineLength

+            return StringUtils.trim( properties.getProperty( "version" ) );

+        }

+        catch ( Exception e )

+        {

+            return null;

+        }

+    }

+

+    static String getMavenVersion( File mavenHome )

+    {

+        File mavenLib = new File( mavenHome, "lib" );

+        File[] jarFiles = mavenLib.listFiles( new FilenameFilter()

+        {

+            public boolean accept( File dir, String name )

+            {

+                return name.endsWith( ".jar" );

+            }

+        } );

+

+        for ( File file : jarFiles )

+        {

+            try

+            {

+                @SuppressWarnings( "deprecation" )

+                URL url =

+                    new URL( "jar:" + file.toURL().toExternalForm()

+                        + "!/META-INF/maven/org.apache.maven/maven-core/pom.properties" );

+

+                Properties properties = new Properties();

+                properties.load( url.openStream() );

+                String version = StringUtils.trim( properties.getProperty( "version" ) );

+                if ( version != null )

+                {

+                    return version;

+                }

+            }

+            catch ( MalformedURLException e )

+            {

+                // ignore

+            }

+            catch ( IOException e )

+            {

+                // ignore

+            }

+        }

+        return null;

+    }

+

+    static boolean isMavenVersion( String mavenSpec )

+    {

+        return isMavenVersion( mavenSpec, getMavenVersion() );

+    }

+

+    static boolean isMavenVersion( String mavenSpec, String actualVersion )

+    {

+        List<String> includes = new ArrayList<String>();

+        List<String> excludes = new ArrayList<String>();

+        parseList( mavenSpec, includes, excludes );

+

+        List<Integer> mavenVersionList = parseVersion( actualVersion );

+

+        return isJreVersion( mavenVersionList, includes, true ) && !isJreVersion( mavenVersionList, excludes, false );

+    }

+

+    static String getJreVersion()

+    {

+        return System.getProperty( "java.version", "" );

+    }

+

+    static String getJreVersion( File javaHome )

+    {

+        // @todo detect actual version

+        return null;

+    }

+

+    static boolean isJreVersion( String jreSpec )

+    {

+        return isJreVersion( jreSpec, getJreVersion() );

+    }

+

+    static boolean isJreVersion( String jreSpec, String actualJreVersion )

+    {

+        List<String> includes = new ArrayList<String>();

+        List<String> excludes = new ArrayList<String>();

+        parseList( jreSpec, includes, excludes );

+

+        List<Integer> jreVersion = parseVersion( actualJreVersion );

+

+        return isJreVersion( jreVersion, includes, true ) && !isJreVersion( jreVersion, excludes, false );

+    }

+

+    static boolean isJreVersion( List<Integer> jreVersion, List<String> versionPatterns, boolean defaultMatch )

+    {

+        if ( versionPatterns != null && !versionPatterns.isEmpty() )

+        {

+            for ( String versionPattern : versionPatterns )

+            {

+                if ( isJreVersion( jreVersion, versionPattern ) )

+                {

+                    return true;

+                }

+            }

+

+            return false;

+        }

+        else

+        {

+            return defaultMatch;

+        }

+    }

+

+    static boolean isJreVersion( List<Integer> jreVersion, String versionPattern )

+    {

+        List<Integer> checkVersion = parseVersion( versionPattern );

+

+        if ( versionPattern.endsWith( "+" ) )

+        {

+            // 1.5+ <=> [1.5,)

+            return compareVersions( jreVersion, checkVersion ) >= 0;

+        }

+        else if ( versionPattern.endsWith( "-" ) )

+        {

+            // 1.5- <=> (,1.5)

+            return compareVersions( jreVersion, checkVersion ) < 0;

+        }

+        else

+        {

+            // 1.5 <=> [1.5,1.6)

+            return checkVersion.size() <= jreVersion.size()

+                && checkVersion.equals( jreVersion.subList( 0, checkVersion.size() ) );

+        }

+    }

+

+    static List<Integer> parseVersion( String version )

+    {

+        version = version.replaceAll( "[^0-9]", "." );

+

+        String[] tokens = StringUtils.split( version, "." );

+

+        List<Integer> numbers = new ArrayList<Integer>();

+

+        for ( String token : tokens )

+        {

+            numbers.add( Integer.valueOf( token ) );

+        }

+

+        return numbers;

+    }

+

+    static int compareVersions( List<Integer> version1, List<Integer> version2 )

+    {

+        for ( Iterator<Integer> it1 = version1.iterator(), it2 = version2.iterator();; )

+        {

+            if ( !it1.hasNext() )

+            {

+                return it2.hasNext() ? -1 : 0;

+            }

+            if ( !it2.hasNext() )

+            {

+                return it1.hasNext() ? 1 : 0;

+            }

+

+            Integer num1 = it1.next();

+            Integer num2 = it2.next();

+

+            int rel = num1.compareTo( num2 );

+            if ( rel != 0 )

+            {

+                return rel;

+            }

+        }

+    }

+

+}

diff --git a/src/main/java/org/apache/maven/plugin/invoker/SystemPropertyPrinter.java b/src/main/java/org/apache/maven/plugins/invoker/SystemPropertyPrinter.java
similarity index 96%
rename from src/main/java/org/apache/maven/plugin/invoker/SystemPropertyPrinter.java
rename to src/main/java/org/apache/maven/plugins/invoker/SystemPropertyPrinter.java
index 6441e82..9c28b1d 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/SystemPropertyPrinter.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/SystemPropertyPrinter.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.invoker;

+package org.apache.maven.plugins.invoker;

 

 /*

  * Licensed to the Apache Software Foundation (ASF) under one

diff --git a/src/main/java/org/apache/maven/plugin/invoker/VerifyMojo.java b/src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java
similarity index 97%
rename from src/main/java/org/apache/maven/plugin/invoker/VerifyMojo.java
rename to src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java
index 5078cd4..6feb0a4 100644
--- a/src/main/java/org/apache/maven/plugin/invoker/VerifyMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java
@@ -1,140 +1,140 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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 org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.invoker.model.io.xpp3.BuildJobXpp3Reader;
-import org.apache.maven.plugins.annotations.LifecyclePhase;
-import org.apache.maven.plugins.annotations.Mojo;
-import org.apache.maven.plugins.annotations.Parameter;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Checks the results of maven-invoker-plugin based integration tests and fails the build if any tests failed.
- *
- * @author Olivier Lamy
- * @since 1.4
- */
-@Mojo( name = "verify", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true )
-public class VerifyMojo
-    extends AbstractMojo
-{
-
-    /**
-     * Flag used to suppress certain invocations. This is useful in tailoring the build using profiles.
-     *
-     * @since 1.1
-     */
-    @Parameter( property = "invoker.skip", defaultValue = "false" )
-    private boolean skipInvocation;
-
-    /**
-     * Base directory where all build reports are read from.
-     *
-     * @since 1.4
-     */
-    @Parameter( property = "invoker.reportsDirectory", defaultValue = "${project.build.directory}/invoker-reports" )
-    private File reportsDirectory;
-
-    /**
-     * A flag controlling whether failures of the sub builds should fail the main build, too. If set to
-     * <code>true</code>, the main build will proceed even if one or more sub builds failed.
-     *
-     * @since 1.3
-     */
-    @Parameter( property = "maven.test.failure.ignore", defaultValue = "false" )
-    private boolean ignoreFailures;
-
-    /**
-     * Flag used to suppress the summary output notifying of successes and failures. If set to <code>true</code>, the
-     * only indication of the build's success or failure will be the effect it has on the main build (if it fails, the
-     * main build should fail as well).
-     */
-    @Parameter( defaultValue = "false" )
-    private boolean suppressSummaries;
-
-    /**
-     * Set this to <code>true</code> to cause a failure if there are no projects to invoke.
-     *
-     * @since 1.9
-     */
-    @Parameter( property = "invoker.failIfNoProjects" )
-    private Boolean failIfNoProjects;
-
-    /**
-     * Invokes Maven on the configured test projects.
-     *
-     * @throws org.apache.maven.plugin.MojoExecutionException If the goal encountered severe errors.
-     * @throws org.apache.maven.plugin.MojoFailureException If any of the Maven builds failed.
-     */
-    public void execute()
-        throws MojoExecutionException, MojoFailureException
-    {
-        if ( skipInvocation )
-        {
-            getLog().info( "Skipping invocation per configuration."
-                               + " If this is incorrect, ensure the skipInvocation parameter is not set to true." );
-            return;
-        }
-
-        File[] reportFiles = ReportUtils.getReportFiles( reportsDirectory );
-        if ( reportFiles.length <= 0 )
-        {
-            if ( Boolean.TRUE.equals( failIfNoProjects ) )
-            {
-                throw new MojoFailureException( "No projects to invoke!" );
-            }
-            getLog().info( "No invoker report files found, nothing to check." );
-            return;
-        }
-
-        InvokerSession invokerSession = new InvokerSession();
-        for ( File reportFile : reportFiles )
-        {
-            try
-            {
-                BuildJobXpp3Reader reader = new BuildJobXpp3Reader();
-                invokerSession.addJob( reader.read( ReaderFactory.newXmlReader( reportFile ) ) );
-            }
-            catch ( XmlPullParserException e )
-            {
-                throw new MojoExecutionException( "Failed to parse report file: " + reportFile, e );
-            }
-            catch ( IOException e )
-            {
-                throw new MojoExecutionException( "Failed to read report file: " + reportFile, e );
-            }
-        }
-
-        if ( !suppressSummaries )
-        {
-            invokerSession.logSummary( getLog(), ignoreFailures );
-        }
-
-        invokerSession.handleFailures( getLog(), ignoreFailures );
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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 org.apache.maven.plugin.AbstractMojo;

+import org.apache.maven.plugin.MojoExecutionException;

+import org.apache.maven.plugin.MojoFailureException;

+import org.apache.maven.plugins.invoker.model.io.xpp3.BuildJobXpp3Reader;

+import org.apache.maven.plugins.annotations.LifecyclePhase;

+import org.apache.maven.plugins.annotations.Mojo;

+import org.apache.maven.plugins.annotations.Parameter;

+import org.codehaus.plexus.util.ReaderFactory;

+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

+

+import java.io.File;

+import java.io.IOException;

+

+/**

+ * Checks the results of maven-invoker-plugin based integration tests and fails the build if any tests failed.

+ *

+ * @author Olivier Lamy

+ * @since 1.4

+ */

+@Mojo( name = "verify", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true )

+public class VerifyMojo

+    extends AbstractMojo

+{

+

+    /**

+     * Flag used to suppress certain invocations. This is useful in tailoring the build using profiles.

+     *

+     * @since 1.1

+     */

+    @Parameter( property = "invoker.skip", defaultValue = "false" )

+    private boolean skipInvocation;

+

+    /**

+     * Base directory where all build reports are read from.

+     *

+     * @since 1.4

+     */

+    @Parameter( property = "invoker.reportsDirectory", defaultValue = "${project.build.directory}/invoker-reports" )

+    private File reportsDirectory;

+

+    /**

+     * A flag controlling whether failures of the sub builds should fail the main build, too. If set to

+     * <code>true</code>, the main build will proceed even if one or more sub builds failed.

+     *

+     * @since 1.3

+     */

+    @Parameter( property = "maven.test.failure.ignore", defaultValue = "false" )

+    private boolean ignoreFailures;

+

+    /**

+     * Flag used to suppress the summary output notifying of successes and failures. If set to <code>true</code>, the

+     * only indication of the build's success or failure will be the effect it has on the main build (if it fails, the

+     * main build should fail as well).

+     */

+    @Parameter( defaultValue = "false" )

+    private boolean suppressSummaries;

+

+    /**

+     * Set this to <code>true</code> to cause a failure if there are no projects to invoke.

+     *

+     * @since 1.9

+     */

+    @Parameter( property = "invoker.failIfNoProjects" )

+    private Boolean failIfNoProjects;

+

+    /**

+     * Invokes Maven on the configured test projects.

+     *

+     * @throws org.apache.maven.plugin.MojoExecutionException If the goal encountered severe errors.

+     * @throws org.apache.maven.plugin.MojoFailureException If any of the Maven builds failed.

+     */

+    public void execute()

+        throws MojoExecutionException, MojoFailureException

+    {

+        if ( skipInvocation )

+        {

+            getLog().info( "Skipping invocation per configuration."

+                               + " If this is incorrect, ensure the skipInvocation parameter is not set to true." );

+            return;

+        }

+

+        File[] reportFiles = ReportUtils.getReportFiles( reportsDirectory );

+        if ( reportFiles.length <= 0 )

+        {

+            if ( Boolean.TRUE.equals( failIfNoProjects ) )

+            {

+                throw new MojoFailureException( "No projects to invoke!" );

+            }

+            getLog().info( "No invoker report files found, nothing to check." );

+            return;

+        }

+

+        InvokerSession invokerSession = new InvokerSession();

+        for ( File reportFile : reportFiles )

+        {

+            try

+            {

+                BuildJobXpp3Reader reader = new BuildJobXpp3Reader();

+                invokerSession.addJob( reader.read( ReaderFactory.newXmlReader( reportFile ) ) );

+            }

+            catch ( XmlPullParserException e )

+            {

+                throw new MojoExecutionException( "Failed to parse report file: " + reportFile, e );

+            }

+            catch ( IOException e )

+            {

+                throw new MojoExecutionException( "Failed to read report file: " + reportFile, e );

+            }

+        }

+

+        if ( !suppressSummaries )

+        {

+            invokerSession.logSummary( getLog(), ignoreFailures );

+        }

+

+        invokerSession.handleFailures( getLog(), ignoreFailures );

+    }

+

+}

diff --git a/src/main/mdo/invocation.mdo b/src/main/mdo/invocation.mdo
index 12505d3..f7016cd 100644
--- a/src/main/mdo/invocation.mdo
+++ b/src/main/mdo/invocation.mdo
@@ -32,7 +32,7 @@
   <defaults>
     <default>
       <key>package</key>
-      <value>org.apache.maven.plugin.invoker.model</value>
+      <value>org.apache.maven.plugins.invoker.model</value>
     </default>
   </defaults>
   <versionDefinition>
diff --git a/src/test/java/org/apache/maven/plugin/invoker/ExtendedMavenProjectStub.java b/src/test/java/org/apache/maven/plugins/invoker/ExtendedMavenProjectStub.java
similarity index 91%
rename from src/test/java/org/apache/maven/plugin/invoker/ExtendedMavenProjectStub.java
rename to src/test/java/org/apache/maven/plugins/invoker/ExtendedMavenProjectStub.java
index 55e71a1..ae9c311 100644
--- a/src/test/java/org/apache/maven/plugin/invoker/ExtendedMavenProjectStub.java
+++ b/src/test/java/org/apache/maven/plugins/invoker/ExtendedMavenProjectStub.java
@@ -1,57 +1,57 @@
-/*
- * 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.
- */
-package org.apache.maven.plugin.invoker;
-
-import org.apache.maven.model.Scm;
-import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
-
-import java.util.Properties;
-
-/**
- * @author Olivier Lamy
- * @since 22 nov. 07
- * @version $Id$
- */
-public class ExtendedMavenProjectStub
-    extends MavenProjectStub
-{
-    private Scm scm;
-
-    private Properties properties;
-
-    public Scm getScm()
-    {
-        return scm;
-    }
-
-    public void setScm( Scm scm )
-    {
-        this.scm = scm;
-    }
-
-    public Properties getProperties()
-    {
-        return properties;
-    }
-
-    public void setProperties( Properties properties )
-    {
-        this.properties = properties;
-    }
-}
+/*

+ * 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.

+ */

+package org.apache.maven.plugins.invoker;

+

+import org.apache.maven.model.Scm;

+import org.apache.maven.plugin.testing.stubs.MavenProjectStub;

+

+import java.util.Properties;

+

+/**

+ * @author Olivier Lamy

+ * @since 22 nov. 07

+ * @version $Id: ExtendedMavenProjectStub.java 1606207 2014-06-27 20:27:03Z khmarbaise $

+ */

+public class ExtendedMavenProjectStub

+    extends MavenProjectStub

+{

+    private Scm scm;

+

+    private Properties properties;

+

+    public Scm getScm()

+    {

+        return scm;

+    }

+

+    public void setScm( Scm scm )

+    {

+        this.scm = scm;

+    }

+

+    public Properties getProperties()

+    {

+        return properties;

+    }

+

+    public void setProperties( Properties properties )

+    {

+        this.properties = properties;

+    }

+}

diff --git a/src/test/java/org/apache/maven/plugin/invoker/InterpolationTest.java b/src/test/java/org/apache/maven/plugins/invoker/InterpolationTest.java
similarity index 95%
rename from src/test/java/org/apache/maven/plugin/invoker/InterpolationTest.java
rename to src/test/java/org/apache/maven/plugins/invoker/InterpolationTest.java
index 2a45dda..a63ac9e 100644
--- a/src/test/java/org/apache/maven/plugin/invoker/InterpolationTest.java
+++ b/src/test/java/org/apache/maven/plugins/invoker/InterpolationTest.java
@@ -1,126 +1,129 @@
-/*
- * 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.
- */
-package org.apache.maven.plugin.invoker;
-
-import java.io.File;
-import java.io.Reader;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.maven.model.Scm;
-import org.apache.maven.plugin.testing.AbstractMojoTestCase;
-import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
-import org.apache.maven.settings.Settings;
-import org.codehaus.plexus.util.IOUtil;
-import org.codehaus.plexus.util.ReaderFactory;
-
-/**
- * @author Olivier Lamy
- * @since 22 nov. 07
- * @version $Id$
- */
-public class InterpolationTest
-    extends AbstractMojoTestCase
-{
-
-    protected MavenProjectStub buildMavenProjectStub()
-    {
-        ExtendedMavenProjectStub project = new ExtendedMavenProjectStub();
-        project.setVersion( "1.0-SNAPSHOT" );
-        project.setArtifactId( "foo" );
-        project.setGroupId( "bar" );
-        Properties properties = new Properties();
-        properties.put( "fooOnProject", "barOnProject" );
-        project.setProperties( properties );
-        Scm scm = new Scm();
-        scm.setConnection( "http://blabla" );
-        project.setScm( scm );
-        return project;
-    }
-
-    public void testCompositeMap()
-        throws Exception
-    {
-
-        Properties properties = new Properties();
-        properties.put( "foo", "bar" );
-        properties.put( "version", "2.0-SNAPSHOT" );
-        CompositeMap compositeMap = new CompositeMap( buildMavenProjectStub(), (Map) properties, false );
-        assertEquals( "1.0-SNAPSHOT", compositeMap.get( "pom.version" ) );
-        assertEquals( "bar", compositeMap.get( "foo" ) );
-        assertEquals( "bar", compositeMap.get( "pom.groupId" ) );
-        assertEquals( "http://blabla", compositeMap.get( "pom.scm.connection" ) );
-        assertEquals( "barOnProject", compositeMap.get( "fooOnProject" ) );
-    }
-
-    public void testPomInterpolation()
-        throws Exception
-    {
-        Reader reader = null;
-        File interpolatedPomFile;
-        try
-        {
-            InvokerMojo invokerMojo = new InvokerMojo();
-            setVariableValueToObject( invokerMojo, "project", buildMavenProjectStub() );
-            setVariableValueToObject( invokerMojo, "settings", new Settings() );
-            Properties properties = new Properties();
-            properties.put( "foo", "bar" );
-            properties.put( "version", "2.0-SNAPSHOT" );
-            setVariableValueToObject( invokerMojo, "filterProperties", properties );
-            String dirPath = getBasedir() + File.separatorChar + "src" + File.separatorChar + "test"
-                + File.separatorChar + "resources" + File.separatorChar + "unit" + File.separatorChar + "interpolation";
-
-            interpolatedPomFile = new File( getBasedir(), "target/interpolated-pom.xml" );
-            invokerMojo.buildInterpolatedFile( new File( dirPath, "pom.xml" ), interpolatedPomFile );
-            reader = ReaderFactory.newXmlReader( interpolatedPomFile );
-            String content = IOUtil.toString( reader );
-            assertTrue( content.indexOf( "<interpolateValue>bar</interpolateValue>" ) > 0 );
-            reader.close();
-            reader = null;
-            // recreate it to test delete if exists before creation
-            invokerMojo.buildInterpolatedFile( new File( dirPath, "pom.xml" ), interpolatedPomFile );
-            reader = ReaderFactory.newXmlReader( interpolatedPomFile );
-            content = IOUtil.toString( reader );
-            assertTrue( content.indexOf( "<interpolateValue>bar</interpolateValue>" ) > 0 );
-            reader.close();
-            reader = null;
-        }
-        finally
-        {
-            IOUtil.close( reader );
-        }
-    }
-
-    public void testProfilesWithNoFile()
-        throws Exception
-    {
-
-        InvokerMojo invokerMojo = new InvokerMojo();
-        setVariableValueToObject( invokerMojo, "profiles", Arrays.asList( "zloug" ) );
-        setVariableValueToObject( invokerMojo, "settings", new Settings() );
-        String dirPath = getBasedir() + File.separatorChar + "src" + File.separatorChar + "test" + File.separatorChar
-            + "resources" + File.separatorChar + "unit" + File.separatorChar + "profiles-from-file";
-        List<String> profiles = invokerMojo.getProfiles( new File( dirPath ) );
-        assertTrue( profiles.contains( "zloug" ) );
-        assertEquals( 1, profiles.size() );
-
-    }
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.Reader;

+import java.util.Arrays;

+import java.util.List;

+import java.util.Map;

+import java.util.Properties;

+

+import org.apache.maven.model.Scm;

+import org.apache.maven.plugin.testing.AbstractMojoTestCase;

+import org.apache.maven.plugin.testing.stubs.MavenProjectStub;

+import org.apache.maven.plugins.invoker.CompositeMap;

+import org.apache.maven.plugins.invoker.InvokerMojo;

+import org.apache.maven.settings.Settings;

+import org.codehaus.plexus.util.IOUtil;

+import org.codehaus.plexus.util.ReaderFactory;

+

+/**

+ * @author Olivier Lamy

+ * @since 22 nov. 07

+ * @version $Id: InterpolationTest.java 1783819 2017-02-21 02:30:23Z schulte $

+ */

+public class InterpolationTest

+    extends AbstractMojoTestCase

+{

+

+    protected MavenProjectStub buildMavenProjectStub()

+    {

+        ExtendedMavenProjectStub project = new ExtendedMavenProjectStub();

+        project.setVersion( "1.0-SNAPSHOT" );

+        project.setArtifactId( "foo" );

+        project.setGroupId( "bar" );

+        Properties properties = new Properties();

+        properties.put( "fooOnProject", "barOnProject" );

+        project.setProperties( properties );

+        Scm scm = new Scm();

+        scm.setConnection( "http://blabla" );

+        project.setScm( scm );

+        return project;

+    }

+

+    public void testCompositeMap()

+        throws Exception

+    {

+

+        Properties properties = new Properties();

+        properties.put( "foo", "bar" );

+        properties.put( "version", "2.0-SNAPSHOT" );

+        CompositeMap compositeMap = new CompositeMap( buildMavenProjectStub(), (Map) properties, false );

+        assertEquals( "1.0-SNAPSHOT", compositeMap.get( "pom.version" ) );

+        assertEquals( "bar", compositeMap.get( "foo" ) );

+        assertEquals( "bar", compositeMap.get( "pom.groupId" ) );

+        assertEquals( "http://blabla", compositeMap.get( "pom.scm.connection" ) );

+        assertEquals( "barOnProject", compositeMap.get( "fooOnProject" ) );

+    }

+

+    public void testPomInterpolation()

+        throws Exception

+    {

+        Reader reader = null;

+        File interpolatedPomFile;

+        try

+        {

+            InvokerMojo invokerMojo = new InvokerMojo();

+            setVariableValueToObject( invokerMojo, "project", buildMavenProjectStub() );

+            setVariableValueToObject( invokerMojo, "settings", new Settings() );

+            Properties properties = new Properties();

+            properties.put( "foo", "bar" );

+            properties.put( "version", "2.0-SNAPSHOT" );

+            setVariableValueToObject( invokerMojo, "filterProperties", properties );

+            String dirPath = getBasedir() + File.separatorChar + "src" + File.separatorChar + "test"

+                + File.separatorChar + "resources" + File.separatorChar + "unit" + File.separatorChar + "interpolation";

+

+            interpolatedPomFile = new File( getBasedir(), "target/interpolated-pom.xml" );

+            invokerMojo.buildInterpolatedFile( new File( dirPath, "pom.xml" ), interpolatedPomFile );

+            reader = ReaderFactory.newXmlReader( interpolatedPomFile );

+            String content = IOUtil.toString( reader );

+            assertTrue( content.indexOf( "<interpolateValue>bar</interpolateValue>" ) > 0 );

+            reader.close();

+            reader = null;

+            // recreate it to test delete if exists before creation

+            invokerMojo.buildInterpolatedFile( new File( dirPath, "pom.xml" ), interpolatedPomFile );

+            reader = ReaderFactory.newXmlReader( interpolatedPomFile );

+            content = IOUtil.toString( reader );

+            assertTrue( content.indexOf( "<interpolateValue>bar</interpolateValue>" ) > 0 );

+            reader.close();

+            reader = null;

+        }

+        finally

+        {

+            IOUtil.close( reader );

+        }

+    }

+

+    public void testProfilesWithNoFile()

+        throws Exception

+    {

+

+        InvokerMojo invokerMojo = new InvokerMojo();

+        setVariableValueToObject( invokerMojo, "profiles", Arrays.asList( "zloug" ) );

+        setVariableValueToObject( invokerMojo, "settings", new Settings() );

+        String dirPath = getBasedir() + File.separatorChar + "src" + File.separatorChar + "test" + File.separatorChar

+            + "resources" + File.separatorChar + "unit" + File.separatorChar + "profiles-from-file";

+        List<String> profiles = invokerMojo.getProfiles( new File( dirPath ) );

+        assertTrue( profiles.contains( "zloug" ) );

+        assertEquals( 1, profiles.size() );

+

+    }

+}

diff --git a/src/test/java/org/apache/maven/plugin/invoker/InvokerMojoTest.java b/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java
similarity index 94%
rename from src/test/java/org/apache/maven/plugin/invoker/InvokerMojoTest.java
rename to src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java
index fc2df8f..68edc64 100644
--- a/src/test/java/org/apache/maven/plugin/invoker/InvokerMojoTest.java
+++ b/src/test/java/org/apache/maven/plugins/invoker/InvokerMojoTest.java
@@ -1,87 +1,87 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.util.Collections;
-import java.util.List;
-
-import org.apache.maven.plugin.invoker.model.BuildJob;
-import org.apache.maven.plugin.testing.AbstractMojoTestCase;
-
-/**
- * @author Olivier Lamy
- * @since 18 nov. 07
- * @version $Id$
- */
-public class InvokerMojoTest
-    extends AbstractMojoTestCase
-{
-
-    public void testSingleInvokerTest()
-        throws Exception
-    {
-        InvokerMojo invokerMojo = new InvokerMojo();
-        String dirPath = getBasedir() + "/src/test/resources/unit";
-        List<String> goals = invokerMojo.getGoals( new File( dirPath ) );
-        assertEquals( 1, goals.size() );
-        setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) );
-        setVariableValueToObject( invokerMojo, "invokerTest", "*dummy*" );
-        BuildJob[] poms = invokerMojo.getBuildJobs();
-        assertEquals( 1, poms.length );
-    }
-
-    public void testMultiInvokerTest()
-        throws Exception
-    {
-        InvokerMojo invokerMojo = new InvokerMojo();
-        String dirPath = getBasedir() + "/src/test/resources/unit";
-        List<String> goals = invokerMojo.getGoals( new File( dirPath ) );
-        assertEquals( 1, goals.size() );
-        setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) );
-        setVariableValueToObject( invokerMojo, "invokerTest", "*dummy*,*terpolatio*" );
-        BuildJob[] poms = invokerMojo.getBuildJobs();
-        assertEquals( 2, poms.length );
-    }
-
-    public void testFullPatternInvokerTest()
-        throws Exception
-    {
-        InvokerMojo invokerMojo = new InvokerMojo();
-        String dirPath = getBasedir() + "/src/test/resources/unit";
-        List<String> goals = invokerMojo.getGoals( new File( dirPath ) );
-        assertEquals( 1, goals.size() );
-        setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) );
-        setVariableValueToObject( invokerMojo, "invokerTest", "*" );
-        BuildJob[] poms = invokerMojo.getBuildJobs();
-        assertEquals( 4, poms.length );
-    }
-
-    public void testAlreadyCloned()
-        throws Exception
-    {
-        assertFalse( AbstractInvokerMojo.alreadyCloned( "dir", Collections.<String>emptyList() ) );
-        assertTrue( AbstractInvokerMojo.alreadyCloned( "dir", Collections.singletonList( "dir" ) ) );
-        assertTrue( AbstractInvokerMojo.alreadyCloned( "dir" + File.separator + "sub",
-                                                       Collections.singletonList( "dir" ) ) );
-        assertFalse( AbstractInvokerMojo.alreadyCloned( "dirs", Collections.singletonList( "dir" ) ) );
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.util.Collections;

+import java.util.List;

+

+import org.apache.maven.plugin.testing.AbstractMojoTestCase;

+import org.apache.maven.plugins.invoker.model.BuildJob;

+

+/**

+ * @author Olivier Lamy

+ * @since 18 nov. 07

+ * @version $Id: InvokerMojoTest.java 1731726 2016-02-22 19:34:37Z khmarbaise $

+ */

+public class InvokerMojoTest

+    extends AbstractMojoTestCase

+{

+

+    public void testSingleInvokerTest()

+        throws Exception

+    {

+        InvokerMojo invokerMojo = new InvokerMojo();

+        String dirPath = getBasedir() + "/src/test/resources/unit";

+        List<String> goals = invokerMojo.getGoals( new File( dirPath ) );

+        assertEquals( 1, goals.size() );

+        setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) );

+        setVariableValueToObject( invokerMojo, "invokerTest", "*dummy*" );

+        BuildJob[] poms = invokerMojo.getBuildJobs();

+        assertEquals( 1, poms.length );

+    }

+

+    public void testMultiInvokerTest()

+        throws Exception

+    {

+        InvokerMojo invokerMojo = new InvokerMojo();

+        String dirPath = getBasedir() + "/src/test/resources/unit";

+        List<String> goals = invokerMojo.getGoals( new File( dirPath ) );

+        assertEquals( 1, goals.size() );

+        setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) );

+        setVariableValueToObject( invokerMojo, "invokerTest", "*dummy*,*terpolatio*" );

+        BuildJob[] poms = invokerMojo.getBuildJobs();

+        assertEquals( 2, poms.length );

+    }

+

+    public void testFullPatternInvokerTest()

+        throws Exception

+    {

+        InvokerMojo invokerMojo = new InvokerMojo();

+        String dirPath = getBasedir() + "/src/test/resources/unit";

+        List<String> goals = invokerMojo.getGoals( new File( dirPath ) );

+        assertEquals( 1, goals.size() );

+        setVariableValueToObject( invokerMojo, "projectsDirectory", new File( dirPath ) );

+        setVariableValueToObject( invokerMojo, "invokerTest", "*" );

+        BuildJob[] poms = invokerMojo.getBuildJobs();

+        assertEquals( 4, poms.length );

+    }

+

+    public void testAlreadyCloned()

+        throws Exception

+    {

+        assertFalse( AbstractInvokerMojo.alreadyCloned( "dir", Collections.<String>emptyList() ) );

+        assertTrue( AbstractInvokerMojo.alreadyCloned( "dir", Collections.singletonList( "dir" ) ) );

+        assertTrue( AbstractInvokerMojo.alreadyCloned( "dir" + File.separator + "sub",

+                                                       Collections.singletonList( "dir" ) ) );

+        assertFalse( AbstractInvokerMojo.alreadyCloned( "dirs", Collections.singletonList( "dir" ) ) );

+    }

+

+}

diff --git a/src/test/java/org/apache/maven/plugin/invoker/InvokerPropertiesTest.java b/src/test/java/org/apache/maven/plugins/invoker/InvokerPropertiesTest.java
similarity index 98%
rename from src/test/java/org/apache/maven/plugin/invoker/InvokerPropertiesTest.java
rename to src/test/java/org/apache/maven/plugins/invoker/InvokerPropertiesTest.java
index 015f199..6d11613 100644
--- a/src/test/java/org/apache/maven/plugin/invoker/InvokerPropertiesTest.java
+++ b/src/test/java/org/apache/maven/plugins/invoker/InvokerPropertiesTest.java
@@ -1,294 +1,295 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.util.Arrays;
-import java.util.Collections;
-import java.util.Properties;
-
-import org.apache.maven.shared.invoker.DefaultInvocationRequest;
-import org.apache.maven.shared.invoker.InvocationRequest;
-
-import junit.framework.TestCase;
-
-/**
- * Tests the invoker properties facade.
- *
- * @author Benjamin Bentmann
- * @version $Id$
- */
-public class InvokerPropertiesTest
-    extends TestCase
-{
-
-    public void testConstructorNullSafe()
-        throws Exception
-    {
-        InvokerProperties facade = new InvokerProperties( null );
-        assertNotNull( facade.getProperties() );
-    }
-
-    public void testGetInvokerProperty()
-        throws Exception
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        assertNull( facade.get( "undefined-key", 0 ) );
-
-        props.setProperty( "key", "value" );
-        assertEquals( "value", facade.get( "key", 1 ) );
-
-        props.setProperty( "key.1", "another-value" );
-        assertEquals( "another-value", facade.get( "key", 1 ) );
-        assertEquals( "value", facade.get( "key", 2 ) );
-    }
-
-    public void testGetJobName()
-        throws Exception
-    {
-        Properties props = new Properties();
-        final String jobName = "Build Job name";
-        props.put( "invoker.name", jobName );
-        InvokerProperties facade = new InvokerProperties( props );
-
-        assertEquals( jobName, facade.getJobName() );
-    }
-
-    public void testIsExpectedResult()
-        throws Exception
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        assertTrue( facade.isExpectedResult( 0, 0 ) );
-        assertFalse( facade.isExpectedResult( 1, 0 ) );
-
-        props.setProperty( "invoker.buildResult", "success" );
-        assertTrue( facade.isExpectedResult( 0, 0 ) );
-        assertFalse( facade.isExpectedResult( 1, 0 ) );
-
-        props.setProperty( "invoker.buildResult", "failure" );
-        assertFalse( facade.isExpectedResult( 0, 0 ) );
-        assertTrue( facade.isExpectedResult( 1, 0 ) );
-    }
-
-    public void testConfigureRequestGoals()
-        throws Exception
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        InvocationRequest request = new DefaultInvocationRequest();
-
-        request.setGoals( Collections.singletonList( "test" ) );
-        facade.configureInvocation( request, 0 );
-        assertEquals( Collections.singletonList( "test" ), request.getGoals() );
-
-        props.setProperty( "invoker.goals", "verify" );
-        facade.configureInvocation( request, 0 );
-        assertEquals( Collections.singletonList( "verify" ), request.getGoals() );
-
-        props.setProperty( "invoker.goals", "   " );
-        facade.configureInvocation( request, 0 );
-        assertEquals( Arrays.asList( new String[0] ), request.getGoals() );
-
-        props.setProperty( "invoker.goals", "  clean , test   verify  " );
-        facade.configureInvocation( request, 0 );
-        assertEquals( Arrays.asList( new String[] { "clean", "test", "verify" } ), request.getGoals() );
-
-        props.setProperty( "invoker.goals", "" );
-        facade.configureInvocation( request, 0 );
-        assertEquals( Arrays.asList( new String[0] ), request.getGoals() );
-    }
-
-    public void testConfigureRequestProfiles()
-        throws Exception
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        InvocationRequest request = new DefaultInvocationRequest();
-
-        request.setProfiles( Collections.singletonList( "test" ) );
-        facade.configureInvocation( request, 0 );
-        assertEquals( Collections.singletonList( "test" ), request.getProfiles() );
-
-        props.setProperty( "invoker.profiles", "verify" );
-        facade.configureInvocation( request, 0 );
-        assertEquals( Collections.singletonList( "verify" ), request.getProfiles() );
-
-        props.setProperty( "invoker.profiles", "   " );
-        facade.configureInvocation( request, 0 );
-        assertEquals( Arrays.asList( new String[0] ), request.getProfiles() );
-
-        props.setProperty( "invoker.profiles", "  clean , test   verify  ," );
-        facade.configureInvocation( request, 0 );
-        assertEquals( Arrays.asList( new String[] { "clean", "test", "verify" } ), request.getProfiles() );
-
-        props.setProperty( "invoker.profiles", "" );
-        facade.configureInvocation( request, 0 );
-        assertEquals( Arrays.asList( new String[0] ), request.getProfiles() );
-    }
-
-    public void testConfigureRequestProject()
-        throws Exception
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        InvocationRequest request = new DefaultInvocationRequest();
-
-        File tempPom = File.createTempFile( "maven-invoker-plugin-test", ".pom" );
-        File tempDir = tempPom.getParentFile();
-
-        request.setBaseDirectory( tempDir );
-        facade.configureInvocation( request, 0 );
-        assertEquals( tempDir, request.getBaseDirectory() );
-        assertEquals( null, request.getPomFile() );
-
-        props.setProperty( "invoker.project", tempPom.getName() );
-        request.setBaseDirectory( tempDir );
-        facade.configureInvocation( request, 0 );
-        assertEquals( tempDir, request.getBaseDirectory() );
-        assertEquals( tempPom, request.getPomFile() );
-
-        props.setProperty( "invoker.project", "" );
-        request.setBaseDirectory( tempDir );
-        facade.configureInvocation( request, 0 );
-        assertEquals( tempDir, request.getBaseDirectory() );
-        assertEquals( null, request.getPomFile() );
-
-        tempPom.delete();
-    }
-
-    public void testConfigureRequestMavenOpts()
-        throws Exception
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        InvocationRequest request = new DefaultInvocationRequest();
-
-        request.setMavenOpts( "default" );
-        facade.configureInvocation( request, 0 );
-        assertEquals( "default", request.getMavenOpts() );
-
-        props.setProperty( "invoker.mavenOpts", "-Xmx512m" );
-        facade.configureInvocation( request, 0 );
-        assertEquals( "-Xmx512m", request.getMavenOpts() );
-    }
-
-    public void testConfigureRequestFailureBehavior()
-        throws Exception
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        InvocationRequest request = new DefaultInvocationRequest();
-
-        request.setReactorFailureBehavior( InvocationRequest.ReactorFailureBehavior.FailAtEnd );
-        facade.configureInvocation( request, 0 );
-        assertEquals( InvocationRequest.ReactorFailureBehavior.FailAtEnd, request.getReactorFailureBehavior() );
-
-        props.setProperty( "invoker.failureBehavior", InvocationRequest.ReactorFailureBehavior.FailNever.getLongOption() );
-        facade.configureInvocation( request, 0 );
-        assertEquals( "fail-never", request.getReactorFailureBehavior().getLongOption() );
-    }
-
-    public void testConfigureRequestRecursion()
-        throws Exception
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        InvocationRequest request = new DefaultInvocationRequest();
-
-        request.setRecursive( true );
-        facade.configureInvocation( request, 0 );
-        assertTrue( request.isRecursive() );
-        request.setRecursive( false );
-        facade.configureInvocation( request, 0 );
-        assertFalse( request.isRecursive() );
-
-        props.setProperty( "invoker.nonRecursive", "true" );
-        facade.configureInvocation( request, 0 );
-        assertFalse( request.isRecursive() );
-
-        props.setProperty( "invoker.nonRecursive", "false" );
-        facade.configureInvocation( request, 0 );
-        assertTrue( request.isRecursive() );
-    }
-
-    public void testConfigureRequestOffline()
-        throws Exception
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        InvocationRequest request = new DefaultInvocationRequest();
-
-        request.setOffline( true );
-        facade.configureInvocation( request, 0 );
-        assertTrue( request.isOffline() );
-        request.setOffline( false );
-        facade.configureInvocation( request, 0 );
-        assertFalse( request.isOffline() );
-
-        props.setProperty( "invoker.offline", "true" );
-        facade.configureInvocation( request, 0 );
-        assertTrue( request.isOffline() );
-
-        props.setProperty( "invoker.offline", "false" );
-        facade.configureInvocation( request, 0 );
-        assertFalse( request.isOffline() );
-    }
-
-    public void testIsInvocationDefined()
-        throws Exception
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        assertFalse( facade.isInvocationDefined( 1 ) );
-
-        props.setProperty( "invoker.goals", "install" );
-        assertFalse( facade.isInvocationDefined( 1 ) );
-
-        props.setProperty( "invoker.goals.2", "install" );
-        assertFalse( facade.isInvocationDefined( 1 ) );
-        assertTrue( facade.isInvocationDefined( 2 ) );
-        assertFalse( facade.isInvocationDefined( 3 ) );
-    }
-    
-    public void testIsSelectedDefined()
-    {
-        Properties props = new Properties();
-        InvokerProperties facade = new InvokerProperties( props );
-
-        assertFalse( facade.isSelectorDefined( 1 ) );
-
-        props.setProperty( "invoker.java.version", "1.6+" );
-        props.setProperty( "invoker.maven.version", "3.0+" );
-        props.setProperty( "invoker.os.family", "windows" );
-        assertFalse( facade.isSelectorDefined( 1 ) );
-
-        props.setProperty( "selector.2.java.version", "1.6+" );
-        props.setProperty( "selector.3.maven.version", "3.0+" );
-        props.setProperty( "selector.4.os.family", "windows" );
-        assertFalse( facade.isSelectorDefined( 1 ) );
-        assertTrue( facade.isSelectorDefined( 2 ) );
-        assertTrue( facade.isSelectorDefined( 3 ) );
-        assertTrue( facade.isSelectorDefined( 4 ) );
-        assertFalse( facade.isSelectorDefined( 5 ) );
-    }
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.util.Arrays;

+import java.util.Collections;

+import java.util.Properties;

+

+import org.apache.maven.plugins.invoker.InvokerProperties;

+import org.apache.maven.shared.invoker.DefaultInvocationRequest;

+import org.apache.maven.shared.invoker.InvocationRequest;

+

+import junit.framework.TestCase;

+

+/**

+ * Tests the invoker properties facade.

+ *

+ * @author Benjamin Bentmann

+ * @version $Id: InvokerPropertiesTest.java 1779250 2017-01-17 20:20:02Z rfscholte $

+ */

+public class InvokerPropertiesTest

+    extends TestCase

+{

+

+    public void testConstructorNullSafe()

+        throws Exception

+    {

+        InvokerProperties facade = new InvokerProperties( null );

+        assertNotNull( facade.getProperties() );

+    }

+

+    public void testGetInvokerProperty()

+        throws Exception

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        assertNull( facade.get( "undefined-key", 0 ) );

+

+        props.setProperty( "key", "value" );

+        assertEquals( "value", facade.get( "key", 1 ) );

+

+        props.setProperty( "key.1", "another-value" );

+        assertEquals( "another-value", facade.get( "key", 1 ) );

+        assertEquals( "value", facade.get( "key", 2 ) );

+    }

+

+    public void testGetJobName()

+        throws Exception

+    {

+        Properties props = new Properties();

+        final String jobName = "Build Job name";

+        props.put( "invoker.name", jobName );

+        InvokerProperties facade = new InvokerProperties( props );

+

+        assertEquals( jobName, facade.getJobName() );

+    }

+

+    public void testIsExpectedResult()

+        throws Exception

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        assertTrue( facade.isExpectedResult( 0, 0 ) );

+        assertFalse( facade.isExpectedResult( 1, 0 ) );

+

+        props.setProperty( "invoker.buildResult", "success" );

+        assertTrue( facade.isExpectedResult( 0, 0 ) );

+        assertFalse( facade.isExpectedResult( 1, 0 ) );

+

+        props.setProperty( "invoker.buildResult", "failure" );

+        assertFalse( facade.isExpectedResult( 0, 0 ) );

+        assertTrue( facade.isExpectedResult( 1, 0 ) );

+    }

+

+    public void testConfigureRequestGoals()

+        throws Exception

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        InvocationRequest request = new DefaultInvocationRequest();

+

+        request.setGoals( Collections.singletonList( "test" ) );

+        facade.configureInvocation( request, 0 );

+        assertEquals( Collections.singletonList( "test" ), request.getGoals() );

+

+        props.setProperty( "invoker.goals", "verify" );

+        facade.configureInvocation( request, 0 );

+        assertEquals( Collections.singletonList( "verify" ), request.getGoals() );

+

+        props.setProperty( "invoker.goals", "   " );

+        facade.configureInvocation( request, 0 );

+        assertEquals( Arrays.asList( new String[0] ), request.getGoals() );

+

+        props.setProperty( "invoker.goals", "  clean , test   verify  " );

+        facade.configureInvocation( request, 0 );

+        assertEquals( Arrays.asList( new String[] { "clean", "test", "verify" } ), request.getGoals() );

+

+        props.setProperty( "invoker.goals", "" );

+        facade.configureInvocation( request, 0 );

+        assertEquals( Arrays.asList( new String[0] ), request.getGoals() );

+    }

+

+    public void testConfigureRequestProfiles()

+        throws Exception

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        InvocationRequest request = new DefaultInvocationRequest();

+

+        request.setProfiles( Collections.singletonList( "test" ) );

+        facade.configureInvocation( request, 0 );

+        assertEquals( Collections.singletonList( "test" ), request.getProfiles() );

+

+        props.setProperty( "invoker.profiles", "verify" );

+        facade.configureInvocation( request, 0 );

+        assertEquals( Collections.singletonList( "verify" ), request.getProfiles() );

+

+        props.setProperty( "invoker.profiles", "   " );

+        facade.configureInvocation( request, 0 );

+        assertEquals( Arrays.asList( new String[0] ), request.getProfiles() );

+

+        props.setProperty( "invoker.profiles", "  clean , test   verify  ," );

+        facade.configureInvocation( request, 0 );

+        assertEquals( Arrays.asList( new String[] { "clean", "test", "verify" } ), request.getProfiles() );

+

+        props.setProperty( "invoker.profiles", "" );

+        facade.configureInvocation( request, 0 );

+        assertEquals( Arrays.asList( new String[0] ), request.getProfiles() );

+    }

+

+    public void testConfigureRequestProject()

+        throws Exception

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        InvocationRequest request = new DefaultInvocationRequest();

+

+        File tempPom = File.createTempFile( "maven-invoker-plugin-test", ".pom" );

+        File tempDir = tempPom.getParentFile();

+

+        request.setBaseDirectory( tempDir );

+        facade.configureInvocation( request, 0 );

+        assertEquals( tempDir, request.getBaseDirectory() );

+        assertEquals( null, request.getPomFile() );

+

+        props.setProperty( "invoker.project", tempPom.getName() );

+        request.setBaseDirectory( tempDir );

+        facade.configureInvocation( request, 0 );

+        assertEquals( tempDir, request.getBaseDirectory() );

+        assertEquals( tempPom, request.getPomFile() );

+

+        props.setProperty( "invoker.project", "" );

+        request.setBaseDirectory( tempDir );

+        facade.configureInvocation( request, 0 );

+        assertEquals( tempDir, request.getBaseDirectory() );

+        assertEquals( null, request.getPomFile() );

+

+        tempPom.delete();

+    }

+

+    public void testConfigureRequestMavenOpts()

+        throws Exception

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        InvocationRequest request = new DefaultInvocationRequest();

+

+        request.setMavenOpts( "default" );

+        facade.configureInvocation( request, 0 );

+        assertEquals( "default", request.getMavenOpts() );

+

+        props.setProperty( "invoker.mavenOpts", "-Xmx512m" );

+        facade.configureInvocation( request, 0 );

+        assertEquals( "-Xmx512m", request.getMavenOpts() );

+    }

+

+    public void testConfigureRequestFailureBehavior()

+        throws Exception

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        InvocationRequest request = new DefaultInvocationRequest();

+

+        request.setReactorFailureBehavior( InvocationRequest.ReactorFailureBehavior.FailAtEnd );

+        facade.configureInvocation( request, 0 );

+        assertEquals( InvocationRequest.ReactorFailureBehavior.FailAtEnd, request.getReactorFailureBehavior() );

+

+        props.setProperty( "invoker.failureBehavior", InvocationRequest.ReactorFailureBehavior.FailNever.getLongOption() );

+        facade.configureInvocation( request, 0 );

+        assertEquals( "fail-never", request.getReactorFailureBehavior().getLongOption() );

+    }

+

+    public void testConfigureRequestRecursion()

+        throws Exception

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        InvocationRequest request = new DefaultInvocationRequest();

+

+        request.setRecursive( true );

+        facade.configureInvocation( request, 0 );

+        assertTrue( request.isRecursive() );

+        request.setRecursive( false );

+        facade.configureInvocation( request, 0 );

+        assertFalse( request.isRecursive() );

+

+        props.setProperty( "invoker.nonRecursive", "true" );

+        facade.configureInvocation( request, 0 );

+        assertFalse( request.isRecursive() );

+

+        props.setProperty( "invoker.nonRecursive", "false" );

+        facade.configureInvocation( request, 0 );

+        assertTrue( request.isRecursive() );

+    }

+

+    public void testConfigureRequestOffline()

+        throws Exception

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        InvocationRequest request = new DefaultInvocationRequest();

+

+        request.setOffline( true );

+        facade.configureInvocation( request, 0 );

+        assertTrue( request.isOffline() );

+        request.setOffline( false );

+        facade.configureInvocation( request, 0 );

+        assertFalse( request.isOffline() );

+

+        props.setProperty( "invoker.offline", "true" );

+        facade.configureInvocation( request, 0 );

+        assertTrue( request.isOffline() );

+

+        props.setProperty( "invoker.offline", "false" );

+        facade.configureInvocation( request, 0 );

+        assertFalse( request.isOffline() );

+    }

+

+    public void testIsInvocationDefined()

+        throws Exception

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        assertFalse( facade.isInvocationDefined( 1 ) );

+

+        props.setProperty( "invoker.goals", "install" );

+        assertFalse( facade.isInvocationDefined( 1 ) );

+

+        props.setProperty( "invoker.goals.2", "install" );

+        assertFalse( facade.isInvocationDefined( 1 ) );

+        assertTrue( facade.isInvocationDefined( 2 ) );

+        assertFalse( facade.isInvocationDefined( 3 ) );

+    }

+    

+    public void testIsSelectedDefined()

+    {

+        Properties props = new Properties();

+        InvokerProperties facade = new InvokerProperties( props );

+

+        assertFalse( facade.isSelectorDefined( 1 ) );

+

+        props.setProperty( "invoker.java.version", "1.6+" );

+        props.setProperty( "invoker.maven.version", "3.0+" );

+        props.setProperty( "invoker.os.family", "windows" );

+        assertFalse( facade.isSelectorDefined( 1 ) );

+

+        props.setProperty( "selector.2.java.version", "1.6+" );

+        props.setProperty( "selector.3.maven.version", "3.0+" );

+        props.setProperty( "selector.4.os.family", "windows" );

+        assertFalse( facade.isSelectorDefined( 1 ) );

+        assertTrue( facade.isSelectorDefined( 2 ) );

+        assertTrue( facade.isSelectorDefined( 3 ) );

+        assertTrue( facade.isSelectorDefined( 4 ) );

+        assertFalse( facade.isSelectorDefined( 5 ) );

+    }

+}

diff --git a/src/test/java/org/apache/maven/plugin/invoker/SelectorTest.java b/src/test/java/org/apache/maven/plugins/invoker/SelectorTest.java
similarity index 94%
rename from src/test/java/org/apache/maven/plugin/invoker/SelectorTest.java
rename to src/test/java/org/apache/maven/plugins/invoker/SelectorTest.java
index 2143702..70886fc 100644
--- a/src/test/java/org/apache/maven/plugin/invoker/SelectorTest.java
+++ b/src/test/java/org/apache/maven/plugins/invoker/SelectorTest.java
@@ -1,4 +1,4 @@
-package org.apache.maven.plugin.invoker;

+package org.apache.maven.plugins.invoker;

 

 /*

  * Licensed to the Apache Software Foundation (ASF) under one

@@ -22,6 +22,8 @@
 import static org.junit.Assert.assertEquals;

 import java.util.Properties;

 

+import org.apache.maven.plugins.invoker.InvokerProperties;

+import org.apache.maven.plugins.invoker.Selector;

 import org.junit.Test;

 

 public class SelectorTest

diff --git a/src/test/java/org/apache/maven/plugin/invoker/SelectorUtilsTest.java b/src/test/java/org/apache/maven/plugins/invoker/SelectorUtilsTest.java
similarity index 97%
rename from src/test/java/org/apache/maven/plugin/invoker/SelectorUtilsTest.java
rename to src/test/java/org/apache/maven/plugins/invoker/SelectorUtilsTest.java
index 71d91f8..02760da 100644
--- a/src/test/java/org/apache/maven/plugin/invoker/SelectorUtilsTest.java
+++ b/src/test/java/org/apache/maven/plugins/invoker/SelectorUtilsTest.java
@@ -1,90 +1,92 @@
-package org.apache.maven.plugin.invoker;
-
-/*
- * 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.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import junit.framework.TestCase;
-
-/**
- * Tests {@link SelectorUtils}.
- *
- * @author Benjamin Bentmann
- */
-public class SelectorUtilsTest
-    extends TestCase
-{
-
-    public void testParseList()
-    {
-        List<String> includes = new ArrayList<String>();
-        List<String> excludes = new ArrayList<String>();
-
-        SelectorUtils.parseList( null, includes, excludes );
-
-        SelectorUtils.parseList( " 1.5, !1.4, 1.6+ ", includes, excludes );
-        assertEquals( Arrays.asList( "1.5", "1.6+" ), includes );
-        assertEquals( Arrays.asList( "1.4" ), excludes );
-    }
-
-    public void testParseVersion()
-    {
-        assertEquals( Arrays.asList( 1, 6, 0, 12 ), SelectorUtils.parseVersion( "1.6.0_12" ) );
-
-        assertEquals( Arrays.asList( 1, 6, 0, 12 ), SelectorUtils.parseVersion( "1.6.0_12+" ) );
-        assertEquals( Arrays.asList( 1, 6, 0, 12 ), SelectorUtils.parseVersion( "1.6.0_12-" ) );
-    }
-
-    public void testCompareVersions()
-    {
-        assertTrue( SelectorUtils.compareVersions( Arrays.asList( 1, 6 ), Arrays.asList( 1, 6 ) ) == 0 );
-
-        assertTrue( SelectorUtils.compareVersions( Arrays.asList( 1, 5 ), Arrays.asList( 1, 6 ) ) < 0 );
-        assertTrue( SelectorUtils.compareVersions( Arrays.asList( 1, 6 ), Arrays.asList( 1, 5 ) ) > 0 );
-
-        assertTrue( SelectorUtils.compareVersions( Arrays.asList( 1 ), Arrays.asList( 1, 6 ) ) < 0 );
-        assertTrue( SelectorUtils.compareVersions( Arrays.asList( 1, 6 ), Arrays.asList( 1 ) ) > 0 );
-    }
-
-    public void testIsMatchingJre()
-    {
-
-        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 4, 2, 8 ), "1.5" ) );
-        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 5 ), "1.5" ) );
-        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 5, 9 ), "1.5" ) );
-        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 6 ), "1.5" ) );
-
-        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 4, 2, 8 ), "1.5+" ) );
-        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 5 ), "1.5+" ) );
-        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 5, 9 ), "1.5+" ) );
-        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 6 ), "1.5+" ) );
-
-        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 4, 2, 8 ), "1.5-" ) );
-        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 5 ), "1.5-" ) );
-        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 5, 9 ), "1.5-" ) );
-        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 6 ), "1.5-" ) );
-
-        assertTrue( SelectorUtils.isJreVersion( (String) null, "1.5" ) );
-        assertTrue( SelectorUtils.isJreVersion( "", "1.5" ) );
-    }
-
-}
+package org.apache.maven.plugins.invoker;

+

+/*

+ * 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.util.ArrayList;

+import java.util.Arrays;

+import java.util.List;

+

+import org.apache.maven.plugins.invoker.SelectorUtils;

+

+import junit.framework.TestCase;

+

+/**

+ * Tests {@link SelectorUtils}.

+ *

+ * @author Benjamin Bentmann

+ */

+public class SelectorUtilsTest

+    extends TestCase

+{

+

+    public void testParseList()

+    {

+        List<String> includes = new ArrayList<String>();

+        List<String> excludes = new ArrayList<String>();

+

+        SelectorUtils.parseList( null, includes, excludes );

+

+        SelectorUtils.parseList( " 1.5, !1.4, 1.6+ ", includes, excludes );

+        assertEquals( Arrays.asList( "1.5", "1.6+" ), includes );

+        assertEquals( Arrays.asList( "1.4" ), excludes );

+    }

+

+    public void testParseVersion()

+    {

+        assertEquals( Arrays.asList( 1, 6, 0, 12 ), SelectorUtils.parseVersion( "1.6.0_12" ) );

+

+        assertEquals( Arrays.asList( 1, 6, 0, 12 ), SelectorUtils.parseVersion( "1.6.0_12+" ) );

+        assertEquals( Arrays.asList( 1, 6, 0, 12 ), SelectorUtils.parseVersion( "1.6.0_12-" ) );

+    }

+

+    public void testCompareVersions()

+    {

+        assertTrue( SelectorUtils.compareVersions( Arrays.asList( 1, 6 ), Arrays.asList( 1, 6 ) ) == 0 );

+

+        assertTrue( SelectorUtils.compareVersions( Arrays.asList( 1, 5 ), Arrays.asList( 1, 6 ) ) < 0 );

+        assertTrue( SelectorUtils.compareVersions( Arrays.asList( 1, 6 ), Arrays.asList( 1, 5 ) ) > 0 );

+

+        assertTrue( SelectorUtils.compareVersions( Arrays.asList( 1 ), Arrays.asList( 1, 6 ) ) < 0 );

+        assertTrue( SelectorUtils.compareVersions( Arrays.asList( 1, 6 ), Arrays.asList( 1 ) ) > 0 );

+    }

+

+    public void testIsMatchingJre()

+    {

+

+        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 4, 2, 8 ), "1.5" ) );

+        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 5 ), "1.5" ) );

+        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 5, 9 ), "1.5" ) );

+        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 6 ), "1.5" ) );

+

+        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 4, 2, 8 ), "1.5+" ) );

+        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 5 ), "1.5+" ) );

+        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 5, 9 ), "1.5+" ) );

+        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 6 ), "1.5+" ) );

+

+        assertTrue( SelectorUtils.isJreVersion( Arrays.asList( 1, 4, 2, 8 ), "1.5-" ) );

+        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 5 ), "1.5-" ) );

+        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 5, 9 ), "1.5-" ) );

+        assertFalse( SelectorUtils.isJreVersion( Arrays.asList( 1, 6 ), "1.5-" ) );

+

+        assertTrue( SelectorUtils.isJreVersion( (String) null, "1.5" ) );

+        assertTrue( SelectorUtils.isJreVersion( "", "1.5" ) );

+    }

+

+}