[1.0,2.0) Versions 1.0 (included) to 2.0 (not included)
*
[1.0,2.0] Versions 1.0 to 2.0 (both included)
*
[1.5,) Versions 1.5 and higher
From 268f9565746175f5900670e372092e0c071d85bd Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Mon, 19 Jul 2021 23:45:50 +0200
Subject: [PATCH 063/188] Use proper term: directory
---
apache-maven/src/bin/mvn.cmd | 2 +-
.../projects/project-builder/it0063/jdk/jre/placeholder.txt | 2 +-
.../it0063/jdk/jre/placeholder.txt | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apache-maven/src/bin/mvn.cmd b/apache-maven/src/bin/mvn.cmd
index b8367f61e3e3..d8f26265f8c8 100644
--- a/apache-maven/src/bin/mvn.cmd
+++ b/apache-maven/src/bin/mvn.cmd
@@ -74,7 +74,7 @@ goto error
set MAVEN_CMD_LINE_ARGS=%*
-@REM Find the project basedir, i.e., the directory that contains the folder ".mvn".
+@REM Find the project basedir, i.e., the directory that contains the directory ".mvn".
@REM Fallback to current working directory if not found.
set "MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%"
diff --git a/maven-core/src/test/projects/project-builder/it0063/jdk/jre/placeholder.txt b/maven-core/src/test/projects/project-builder/it0063/jdk/jre/placeholder.txt
index e26e86087ce3..4a9eb145a1e3 100644
--- a/maven-core/src/test/projects/project-builder/it0063/jdk/jre/placeholder.txt
+++ b/maven-core/src/test/projects/project-builder/it0063/jdk/jre/placeholder.txt
@@ -1 +1 @@
-need it so that empty folder does not get deleted
\ No newline at end of file
+need it so that empty directory does not get deleted
diff --git a/maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt b/maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt
index e26e86087ce3..4a9eb145a1e3 100644
--- a/maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt
+++ b/maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt
@@ -1 +1 @@
-need it so that empty folder does not get deleted
\ No newline at end of file
+need it so that empty directory does not get deleted
From 25df095829bff8a1744db7dbf1ddd14aa1f8d43f Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Mon, 19 Jul 2021 23:56:22 +0200
Subject: [PATCH 064/188] [MNG-7190] Load mavenrc from /usr/local/etc also in
Bourne shell script
---
apache-maven/src/bin/mvn | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/apache-maven/src/bin/mvn b/apache-maven/src/bin/mvn
index 1d429303a6b1..cc2cdacba096 100755
--- a/apache-maven/src/bin/mvn
+++ b/apache-maven/src/bin/mvn
@@ -29,6 +29,10 @@
if [ -z "$MAVEN_SKIP_RC" ] ; then
+ if [ -f /usr/local/etc/mavenrc ] ; then
+ . /usr/local/etc/mavenrc
+ fi
+
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
From c395ca976dc9eaed65dcdc0037508d1edbfb57f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Herv=C3=A9=20Boutemy?=
Date: Tue, 20 Jul 2021 22:41:03 +0200
Subject: [PATCH 065/188] [MNG-7190] add /usr/local/etc/mavenrc to reference
documentation
---
apache-maven/src/site/apt/index.apt.vm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/apache-maven/src/site/apt/index.apt.vm b/apache-maven/src/site/apt/index.apt.vm
index 994aeab1d9eb..1d802661d98f 100644
--- a/apache-maven/src/site/apt/index.apt.vm
+++ b/apache-maven/src/site/apt/index.apt.vm
@@ -31,9 +31,9 @@ ${project.name}
* <<>> invocation can be customised through:
- * <<>> and <<<~/.mavenrc>>> scripts on Unix,
+ * <<>> (since 3.8.2), <<>> and <<<$HOME/.mavenrc>>> scripts on Unix,
- * <<<~\mavenrc_pre.bat>>> and <<<~\mavenrc_pre.cmd>>> scripts on Windows,
+ * <<<%USERPROFILE%\\mavenrc_pre.bat>>> and <<<%USERPROFILE%\\mavenrc_pre.cmd>>> scripts on Windows,
[]
From b74199ed446c83282ad806afaf962a7f74eac0ea Mon Sep 17 00:00:00 2001
From: Guillaume Nodet
Date: Wed, 25 Nov 2020 20:12:04 +0100
Subject: [PATCH 066/188] [MNG-7034] StackOverflowError thrown if a cycle
exists in BOM imports
This closes #484
---
.../model/building/DefaultModelBuilder.java | 11 +-
.../building/DefaultModelBuilderTest.java | 153 ++++++++++++++++++
2 files changed, 162 insertions(+), 2 deletions(-)
create mode 100644 maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
index a8568efb2753..a089f9d991df 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
@@ -248,6 +248,13 @@ public DefaultModelBuilder setReportingConverter( ReportingConverter reportingCo
@Override
public ModelBuildingResult build( ModelBuildingRequest request )
throws ModelBuildingException
+ {
+ return build( request, new LinkedHashSet() );
+ }
+
+ @SuppressWarnings( "checkstyle:methodlength" )
+ protected ModelBuildingResult build( ModelBuildingRequest request, Collection importIds )
+ throws ModelBuildingException
{
// phase 1
DefaultModelBuildingResult result = new DefaultModelBuildingResult();
@@ -427,7 +434,7 @@ else if ( !parentIds.add( parentData.getId() ) )
if ( !request.isTwoPhaseBuilding() )
{
- build( request, result );
+ build( request, result, importIds );
}
return result;
@@ -1303,7 +1310,7 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque
final ModelBuildingResult importResult;
try
{
- importResult = build( importRequest );
+ importResult = build( importRequest, importIds );
}
catch ( ModelBuildingException e )
{
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java
new file mode 100644
index 000000000000..4e7919a6c2ed
--- /dev/null
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java
@@ -0,0 +1,153 @@
+package org.apache.maven.model.building;
+
+ /*
+ * 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.model.Dependency;
+import org.apache.maven.model.Parent;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.resolution.InvalidRepositoryException;
+import org.apache.maven.model.resolution.ModelResolver;
+import org.apache.maven.model.resolution.UnresolvableModelException;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author Guillaume Nodet
+ */
+public class DefaultModelBuilderTest
+{
+
+ private static final String BASE1_ID = "thegroup:base1:pom";
+ private static final String BASE1_ID2 = "thegroup:base1:1";
+
+ private static final String BASE1 = "\n" +
+ " 4.0.0\n" +
+ " thegroup\n" +
+ " base1\n" +
+ " 1\n" +
+ " pom\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " thegroup\n" +
+ " base2\n" +
+ " 1\n" +
+ " pom\n" +
+ " import\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ "\n";
+
+ private static final String BASE2_ID = "thegroup:base2:pom";
+ private static final String BASE2_ID2 = "thegroup:base2:1";
+
+ private static final String BASE2 = "\n" +
+ " 4.0.0\n" +
+ " thegroup\n" +
+ " base2\n" +
+ " 1\n" +
+ " pom\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " thegroup\n" +
+ " base1\n" +
+ " 1\n" +
+ " pom\n" +
+ " import\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ "\n";
+
+ @Test( expected = ModelBuildingException.class )
+ public void testCycleInImports()
+ throws Exception
+ {
+ ModelBuilder builder = new DefaultModelBuilderFactory().newInstance();
+ assertNotNull( builder );
+
+ DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
+ request.setModelSource( new StringModelSource( BASE1 ) );
+ request.setModelResolver( new CycleInImportsResolver() );
+
+ builder.build( request );
+ }
+
+ static class CycleInImportsResolver extends BaseModelResolver
+ {
+ @Override
+ public ModelSource resolveModel(Dependency dependency) throws UnresolvableModelException
+ {
+ switch ( dependency.getManagementKey() )
+ {
+ case BASE1_ID: return new StringModelSource( BASE1 );
+ case BASE2_ID: return new StringModelSource( BASE2 );
+ }
+ return null;
+ }
+ }
+
+ static class BaseModelResolver implements ModelResolver
+ {
+ @Override
+ public ModelSource resolveModel( String groupId, String artifactId, String version )
+ throws UnresolvableModelException
+ {
+ switch ( groupId + ":" + artifactId + ":" + version )
+ {
+ case BASE1_ID2: return new StringModelSource( BASE1 );
+ case BASE2_ID2: return new StringModelSource( BASE2 );
+ }
+ return null;
+ }
+
+ @Override
+ public ModelSource resolveModel( Parent parent ) throws UnresolvableModelException
+ {
+ return null;
+ }
+
+ @Override
+ public ModelSource resolveModel( Dependency dependency ) throws UnresolvableModelException
+ {
+ return null;
+ }
+
+ @Override
+ public void addRepository( Repository repository ) throws InvalidRepositoryException
+ {
+ }
+
+ @Override
+ public void addRepository(Repository repository, boolean replace) throws InvalidRepositoryException
+ {
+ }
+
+ @Override
+ public ModelResolver newCopy()
+ {
+ return this;
+ }
+ }
+
+}
From 22a8cfa05976b23284388675dcabd7e5e8037fb0 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Thu, 22 Jul 2021 21:07:03 +0200
Subject: [PATCH 067/188] [MNG-6648] 'mavenrc_pre' script does not receive
arguments like mavenrc in Bourne shell does
This closes #511
---
apache-maven/src/bin/mvn.cmd | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/apache-maven/src/bin/mvn.cmd b/apache-maven/src/bin/mvn.cmd
index d8f26265f8c8..0faa39f81de8 100644
--- a/apache-maven/src/bin/mvn.cmd
+++ b/apache-maven/src/bin/mvn.cmd
@@ -35,8 +35,8 @@
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
-if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat"
-if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd"
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
From f32eb09892686cba083f9f175b3c8eac0ac42ae7 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Fri, 23 Jul 2021 22:45:34 +0200
Subject: [PATCH 068/188] [MNG-7010] Omit "NB: JAVA_HOME should point to a JDK
not a JRE"
This closes #512
---
apache-maven/src/bin/mvn | 5 ++---
apache-maven/src/bin/mvn.cmd | 5 ++---
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/apache-maven/src/bin/mvn b/apache-maven/src/bin/mvn
index cc2cdacba096..29e0eabb837c 100755
--- a/apache-maven/src/bin/mvn
+++ b/apache-maven/src/bin/mvn
@@ -100,9 +100,8 @@ else
fi
if [ ! -x "$JAVACMD" ] ; then
- echo "The JAVA_HOME environment variable is not defined correctly" >&2
- echo "This environment variable is needed to run this program" >&2
- echo "NB: JAVA_HOME should point to a JDK not a JRE" >&2
+ echo "The JAVA_HOME environment variable is not defined correctly," >&2
+ echo "this environment variable is needed to run this program." >&2
exit 1
fi
diff --git a/apache-maven/src/bin/mvn.cmd b/apache-maven/src/bin/mvn.cmd
index 0faa39f81de8..fcb0f455a804 100644
--- a/apache-maven/src/bin/mvn.cmd
+++ b/apache-maven/src/bin/mvn.cmd
@@ -54,9 +54,8 @@ set "JAVACMD=%JAVA_HOME%\bin\java.exe"
:checkJCmd
if exist "%JAVACMD%" goto chkMHome
-echo The JAVA_HOME environment variable is not defined correctly >&2
-echo This environment variable is needed to run this program >&2
-echo NB: JAVA_HOME should point to a JDK not a JRE >&2
+echo The JAVA_HOME environment variable is not defined correctly, >&2
+echo this environment variable is needed to run this program. >&2
goto error
:chkMHome
From 51f6d8b8525d8bf218f70100ec99a7ae97097923 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Sun, 25 Jul 2021 14:32:31 +0200
Subject: [PATCH 069/188] [MNG-7196] Upgrade Jansi to 2.3.4
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index dbe5eb2de604..750e63b1eeb8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -294,7 +294,7 @@ under the License.
org.fusesource.jansijansi
- 2.3.3
+ 2.3.4org.slf4j
From 7ecdb3c970d71de3e48fe4de691388868ac03630 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Tue, 27 Jul 2021 14:58:11 +0200
Subject: [PATCH 070/188] [MNG-7198] Upgrade SLF4J to 1.7.32
---
.../{MIT-slf4j-api-1.7.30.txt => MIT-slf4j-api-1.7.32.txt} | 0
pom.xml | 2 +-
2 files changed, 1 insertion(+), 1 deletion(-)
rename apache-maven/src/main/appended-resources/licenses/{MIT-slf4j-api-1.7.30.txt => MIT-slf4j-api-1.7.32.txt} (100%)
diff --git a/apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.30.txt b/apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.32.txt
similarity index 100%
rename from apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.30.txt
rename to apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.32.txt
diff --git a/pom.xml b/pom.xml
index 750e63b1eeb8..318141ea1899 100644
--- a/pom.xml
+++ b/pom.xml
@@ -66,7 +66,7 @@ under the License.
1.111.31.6.3
- 1.7.30
+ 1.7.322.2.11.7.4true
From ea98e05a04480131370aa0c110b8c54cf726c06f Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Wed, 4 Aug 2021 21:03:30 +0200
Subject: [PATCH 071/188] [maven-release-plugin] prepare release maven-3.8.2
---
apache-maven/pom.xml | 2 +-
maven-artifact/pom.xml | 2 +-
maven-builder-support/pom.xml | 2 +-
maven-compat/pom.xml | 2 +-
maven-core/pom.xml | 2 +-
maven-embedder/pom.xml | 2 +-
maven-model-builder/pom.xml | 2 +-
maven-model/pom.xml | 2 +-
maven-plugin-api/pom.xml | 2 +-
maven-repository-metadata/pom.xml | 2 +-
maven-resolver-provider/pom.xml | 2 +-
maven-settings-builder/pom.xml | 2 +-
maven-settings/pom.xml | 2 +-
maven-slf4j-provider/pom.xml | 2 +-
pom.xml | 6 +++---
15 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml
index 6e267ad5e25a..42491b3feb84 100644
--- a/apache-maven/pom.xml
+++ b/apache-maven/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2apache-maven
diff --git a/maven-artifact/pom.xml b/maven-artifact/pom.xml
index 6b2aabfeebe7..d085c96530d2 100644
--- a/maven-artifact/pom.xml
+++ b/maven-artifact/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-artifact
diff --git a/maven-builder-support/pom.xml b/maven-builder-support/pom.xml
index ed0df18ec467..af3608dbb1a5 100644
--- a/maven-builder-support/pom.xml
+++ b/maven-builder-support/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-builder-support
diff --git a/maven-compat/pom.xml b/maven-compat/pom.xml
index 55f4f2575342..161764395933 100644
--- a/maven-compat/pom.xml
+++ b/maven-compat/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-compat
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index dc5a422e202a..7c7b722310ce 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-core
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index 2edf4171d63b..637a408cf40b 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-embedder
diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml
index a383fefe3e4f..1365b6b64026 100644
--- a/maven-model-builder/pom.xml
+++ b/maven-model-builder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-model-builder
diff --git a/maven-model/pom.xml b/maven-model/pom.xml
index cd9a63940231..c99d8e337fe2 100644
--- a/maven-model/pom.xml
+++ b/maven-model/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-model
diff --git a/maven-plugin-api/pom.xml b/maven-plugin-api/pom.xml
index 3d93184524ee..8ac3cfbb5037 100644
--- a/maven-plugin-api/pom.xml
+++ b/maven-plugin-api/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-plugin-api
diff --git a/maven-repository-metadata/pom.xml b/maven-repository-metadata/pom.xml
index b1ec1e540fb1..486e26e04be5 100644
--- a/maven-repository-metadata/pom.xml
+++ b/maven-repository-metadata/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-repository-metadata
diff --git a/maven-resolver-provider/pom.xml b/maven-resolver-provider/pom.xml
index 355a4ebab0c4..d4a1c61363e9 100644
--- a/maven-resolver-provider/pom.xml
+++ b/maven-resolver-provider/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-resolver-provider
diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml
index ee196b75d804..055eb0dbb485 100644
--- a/maven-settings-builder/pom.xml
+++ b/maven-settings-builder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-settings-builder
diff --git a/maven-settings/pom.xml b/maven-settings/pom.xml
index bdc4c0f435bf..606550eea8fa 100644
--- a/maven-settings/pom.xml
+++ b/maven-settings/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-settings
diff --git a/maven-slf4j-provider/pom.xml b/maven-slf4j-provider/pom.xml
index b896f9548acd..b4280ce7a460 100644
--- a/maven-slf4j-provider/pom.xml
+++ b/maven-slf4j-provider/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2-SNAPSHOT
+ 3.8.2maven-slf4j-provider
diff --git a/pom.xml b/pom.xml
index 318141ea1899..1875b9f65b72 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,7 @@ under the License.
maven
- 3.8.2-SNAPSHOT
+ 3.8.2pomApache Maven
@@ -77,7 +77,7 @@ under the License.
ref/3-LATESTNone**/package-info.java
- 2019-11-07T12:32:18Z
+ 2021-08-04T18:57:55Z
@@ -101,7 +101,7 @@ under the License.
scm:git:https://gitbox.apache.org/repos/asf/maven.gitscm:git:https://gitbox.apache.org/repos/asf/maven.githttps://github.com/apache/maven/tree/${project.scm.tag}
- maven-3.8.x
+ maven-3.8.2jira
From 865dcaa6fffc8fbc679f190280e1f0f7b1d783b5 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Wed, 4 Aug 2021 21:03:42 +0200
Subject: [PATCH 072/188] [maven-release-plugin] prepare for next development
iteration
---
apache-maven/pom.xml | 2 +-
maven-artifact/pom.xml | 2 +-
maven-builder-support/pom.xml | 2 +-
maven-compat/pom.xml | 2 +-
maven-core/pom.xml | 2 +-
maven-embedder/pom.xml | 2 +-
maven-model-builder/pom.xml | 2 +-
maven-model/pom.xml | 2 +-
maven-plugin-api/pom.xml | 2 +-
maven-repository-metadata/pom.xml | 2 +-
maven-resolver-provider/pom.xml | 2 +-
maven-settings-builder/pom.xml | 2 +-
maven-settings/pom.xml | 2 +-
maven-slf4j-provider/pom.xml | 2 +-
pom.xml | 4 ++--
15 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml
index 42491b3feb84..2cc6ca31d533 100644
--- a/apache-maven/pom.xml
+++ b/apache-maven/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTapache-maven
diff --git a/maven-artifact/pom.xml b/maven-artifact/pom.xml
index d085c96530d2..5203f1b79592 100644
--- a/maven-artifact/pom.xml
+++ b/maven-artifact/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-artifact
diff --git a/maven-builder-support/pom.xml b/maven-builder-support/pom.xml
index af3608dbb1a5..191bfc5967d0 100644
--- a/maven-builder-support/pom.xml
+++ b/maven-builder-support/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-builder-support
diff --git a/maven-compat/pom.xml b/maven-compat/pom.xml
index 161764395933..06686b980a5d 100644
--- a/maven-compat/pom.xml
+++ b/maven-compat/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-compat
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index 7c7b722310ce..60b958f1f6fb 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-core
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index 637a408cf40b..e0b647902053 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-embedder
diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml
index 1365b6b64026..06d42d38e31b 100644
--- a/maven-model-builder/pom.xml
+++ b/maven-model-builder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-model-builder
diff --git a/maven-model/pom.xml b/maven-model/pom.xml
index c99d8e337fe2..0e002c0c2f5e 100644
--- a/maven-model/pom.xml
+++ b/maven-model/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-model
diff --git a/maven-plugin-api/pom.xml b/maven-plugin-api/pom.xml
index 8ac3cfbb5037..a0a708926b69 100644
--- a/maven-plugin-api/pom.xml
+++ b/maven-plugin-api/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-plugin-api
diff --git a/maven-repository-metadata/pom.xml b/maven-repository-metadata/pom.xml
index 486e26e04be5..b4ac0f489b00 100644
--- a/maven-repository-metadata/pom.xml
+++ b/maven-repository-metadata/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-repository-metadata
diff --git a/maven-resolver-provider/pom.xml b/maven-resolver-provider/pom.xml
index d4a1c61363e9..70e0f4e5bc35 100644
--- a/maven-resolver-provider/pom.xml
+++ b/maven-resolver-provider/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-resolver-provider
diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml
index 055eb0dbb485..a85c8a8c1191 100644
--- a/maven-settings-builder/pom.xml
+++ b/maven-settings-builder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-settings-builder
diff --git a/maven-settings/pom.xml b/maven-settings/pom.xml
index 606550eea8fa..6fa967c38ca3 100644
--- a/maven-settings/pom.xml
+++ b/maven-settings/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-settings
diff --git a/maven-slf4j-provider/pom.xml b/maven-slf4j-provider/pom.xml
index b4280ce7a460..802d226c9c0a 100644
--- a/maven-slf4j-provider/pom.xml
+++ b/maven-slf4j-provider/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.2
+ 3.8.3-SNAPSHOTmaven-slf4j-provider
diff --git a/pom.xml b/pom.xml
index 1875b9f65b72..05b80b2db065 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,7 @@ under the License.
maven
- 3.8.2
+ 3.8.3-SNAPSHOTpomApache Maven
@@ -77,7 +77,7 @@ under the License.
ref/3-LATESTNone**/package-info.java
- 2021-08-04T18:57:55Z
+ 2021-08-04T19:03:41Z
From 9adb3aedf21ca9a49560957e0e1b9125266bb401 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Fri, 13 Aug 2021 21:59:19 +0200
Subject: [PATCH 073/188] Document Maven 3.8.1 and 3.8.2 releases
---
doap_Maven.rdf | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/doap_Maven.rdf b/doap_Maven.rdf
index 45b4e4bef3e4..0417fff803ea 100644
--- a/doap_Maven.rdf
+++ b/doap_Maven.rdf
@@ -33,6 +33,24 @@ under the License.
Latest stable release
+ 2021-08-04
+ 3.8.2
+ http://archive.apache.org/dist/maven/maven-3/3.8.2/binaries/apache-maven-3.8.2-bin.zip
+ http://archive.apache.org/dist/maven/maven-3/3.8.2/binaries/apache-maven-3.8.2-bin.tar.gz
+ http://archive.apache.org/dist/maven/maven-3/3.8.2/source/apache-maven-3.8.2-src.zip
+ http://archive.apache.org/dist/maven/maven-3/3.8.2/source/apache-maven-3.8.2-src.tar.gz
+
+
+ Latest stable release
+ 2021-04-04
+ 3.8.1
+ http://archive.apache.org/dist/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.zip
+ http://archive.apache.org/dist/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.tar.gz
+ http://archive.apache.org/dist/maven/maven-3/3.8.1/source/apache-maven-3.8.1-src.zip
+ http://archive.apache.org/dist/maven/maven-3/3.8.1/source/apache-maven-3.8.1-src.tar.gz
+
+
+ Apache Maven 3.6.22019-08-273.6.2http://archive.apache.org/dist/maven/maven-3/3.6.2/binaries/apache-maven-3.6.2-bin.zip
From 4dc115967a9ac1522fe01d33de1a3279d52a559a Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Sat, 14 Aug 2021 10:27:09 +0200
Subject: [PATCH 074/188] Fix DOAP
---
doap_Maven.rdf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doap_Maven.rdf b/doap_Maven.rdf
index 0417fff803ea..531df1217a61 100644
--- a/doap_Maven.rdf
+++ b/doap_Maven.rdf
@@ -41,7 +41,7 @@ under the License.
http://archive.apache.org/dist/maven/maven-3/3.8.2/source/apache-maven-3.8.2-src.tar.gz
- Latest stable release
+ Apache Maven 3.8.12021-04-043.8.1http://archive.apache.org/dist/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.zip
From 547dfddb2ef02f44d9f2d0730348eaedfcd2e126 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Wed, 22 Jan 2020 09:25:24 +0100
Subject: [PATCH 075/188] Improve license handling
* Stream line the output of the license listing
* Exclude jsoup from final distribution since we only need its license information
* Use proper SPDX ID for our license
This closes #317
---
apache-maven/pom.xml | 6 +++---
.../appended-resources/META-INF/LICENSE.vm | 19 +++++++++++--------
.../licenses/{ASL-2.0.txt => Apache-2.0.txt} | 0
apache-maven/src/main/assembly/component.xml | 1 +
4 files changed, 15 insertions(+), 11 deletions(-)
rename apache-maven/src/main/appended-resources/licenses/{ASL-2.0.txt => Apache-2.0.txt} (100%)
diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml
index 2cc6ca31d533..a4cf0396c61b 100644
--- a/apache-maven/pom.xml
+++ b/apache-maven/pom.xml
@@ -79,10 +79,10 @@ under the License.
+
-
org.jsoupjsoupruntime
diff --git a/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm b/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
index 25ac46f3770f..43357d142ef0 100644
--- a/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
+++ b/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
@@ -18,21 +18,21 @@
##
-Apache Maven includes a number of components and libraries with separate
-copyright notices and license terms. Your use of those components are
-subject to the terms and conditions of the following licenses:
+Apache Maven includes a number of components and libraries with separate
+copyright notices and license terms. Your use of those components are
+subject to the terms and conditions of the following licenses:
##
#set ( $apacheMavenGroupIds = [ "org.apache.maven", "org.apache.maven.wagon", "org.apache.maven.resolver",
"org.apache.maven.shared" ] )
#set ( $MITLicenseNames = [ "MIT License", "MIT license", "The MIT License" ] )
#foreach ( $project in $projects )
-#**##foreach ( $license in $project.licenses)
+#**##foreach ( $license in $project.licenses )
#* *##set ( $groupId = $project.artifact.groupId )
#* *##set ( $directory = 'lib' )
#* *##if ( !$apacheMavenGroupIds.contains( $groupId ) )
#* *### advertise about each non-Maven dependency
#* *###
-#* *### infer SPDX license code
+#* *### infer SPDX license id
#* *##if ( $license.name == "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0" )
#* *##set ( $spdx = 'CDDL-1.0' )
#* *##elseif ( $MITLicenseNames.contains( $license.name ) )
@@ -40,7 +40,7 @@ subject to the terms and conditions of the following licenses:
#* *##elseif ( $license.name == "Eclipse Public License, Version 1.0" )
#* *##set ( $spdx = 'EPL-1.0' )
#* *##elseif ( $license.url.contains( "www.apache.org/licenses/LICENSE-2.0" ) )
-#* *##set ( $spdx = 'ASL-2.0' )
+#* *##set ( $spdx = 'Apache-2.0' )
#* *##else
#* *### unrecognized license will require analysis to know obligations
#* *##set ( $spdx = 'unrecognized' )
@@ -68,13 +68,16 @@ subject to the terms and conditions of the following licenses:
#* *##else
#* *##set ( $downloaded = $locator.getResourceAsFile( "licenses/${spdx}.txt", "licenses/${licFile}" ) )
#* *##end
+
#* *### add dependency info to output
- $directory/${project.artifact.artifactId}-${project.artifact.version}.jar: $project.artifact.toString().replace( ':eclipse-plugin:', ':jar:' )
- $project.name
+ Project: $project.name
#if ( $project.url )Project URL: ${project.url}#end
- License: $license.name#if ( $spdx ) ($spdx)#end $license.url ($licFile)
+ License: $license.name#if ( $spdx ) ($spdx)#end
+
+ License URL: $license.url ($licFile)
#* *##end
#**##end
diff --git a/apache-maven/src/main/appended-resources/licenses/ASL-2.0.txt b/apache-maven/src/main/appended-resources/licenses/Apache-2.0.txt
similarity index 100%
rename from apache-maven/src/main/appended-resources/licenses/ASL-2.0.txt
rename to apache-maven/src/main/appended-resources/licenses/Apache-2.0.txt
diff --git a/apache-maven/src/main/assembly/component.xml b/apache-maven/src/main/assembly/component.xml
index 4f9ff1662854..657d06bf026b 100644
--- a/apache-maven/src/main/assembly/component.xml
+++ b/apache-maven/src/main/assembly/component.xml
@@ -31,6 +31,7 @@ under the License.
liborg.codehaus.plexus:plexus-classworlds
+ org.jsoup:jsoup
From 0c3fe074bbd3272a7b46c28683c6ed50d0daede7 Mon Sep 17 00:00:00 2001
From: Karl Heinz Marbaise
Date: Mon, 9 Dec 2019 19:43:44 +0100
Subject: [PATCH 076/188] [MNG-6818] - Upgrade plexus-utils 3.3.0
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 05b80b2db065..82128161c01c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,7 +56,7 @@ under the License.
2.21.02.1.01.25
- 3.2.1
+ 3.3.04.2.20.3.43.4.3
From ccafe8bf46ad874ca0cfba6ea5961b34f1630f82 Mon Sep 17 00:00:00 2001
From: "artem.krosheninnikov"
Date: Sun, 5 Jan 2020 22:24:21 +0300
Subject: [PATCH 077/188] [MNG-6841] update plexus-interpolation to 1.26
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 82128161c01c..4a4f69ba3f0a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,7 +55,7 @@ under the License.
4.122.21.02.1.0
- 1.25
+ 1.263.3.04.2.20.3.4
From c76c9d9116b4626c20abe26c025623797249f997 Mon Sep 17 00:00:00 2001
From: Tamas Cservenak
Date: Fri, 10 Sep 2021 14:33:45 +0200
Subject: [PATCH 078/188] [MNG-7246] Upgrade Plexus Cipher and Sec Dispatcher
to 2.0
Both plexus-cipher and plexus-sec-dispatcher have had a
groupId change, but plexus-cipher change was implemented
for 1.8 version.
Latest versions of artifacts are 2.0. This PR
ups plexus-cipher version and adds proper changes
for plexus-sec-dispatcher groupId change.
This closes #534
---
.../project-with-inheritance/pom.xml | 2 +-
.../project-with-inheritance/pom.xml | 2 +-
.../org/apache/maven/lifecycle/pom.xml | 2 +-
maven-embedder/pom.xml | 2 +-
maven-settings-builder/pom.xml | 2 +-
pom.xml | 17 ++++++-----------
6 files changed, 11 insertions(+), 16 deletions(-)
diff --git a/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml b/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml
index c9a894d9059b..7d0850e48382 100644
--- a/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml
+++ b/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml
@@ -473,7 +473,7 @@ under the License.
${mercuryMp3Version}
- org.sonatype.plexus
+ org.codehaus.plexusplexus-sec-dispatcher${securityDispatcherVersion}
diff --git a/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml b/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml
index c9a894d9059b..7d0850e48382 100644
--- a/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml
+++ b/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml
@@ -473,7 +473,7 @@ under the License.
${mercuryMp3Version}
- org.sonatype.plexus
+ org.codehaus.plexusplexus-sec-dispatcher${securityDispatcherVersion}
diff --git a/maven-core/src/test/resources/org/apache/maven/lifecycle/pom.xml b/maven-core/src/test/resources/org/apache/maven/lifecycle/pom.xml
index 531e5510c5a7..5caaac1ba285 100644
--- a/maven-core/src/test/resources/org/apache/maven/lifecycle/pom.xml
+++ b/maven-core/src/test/resources/org/apache/maven/lifecycle/pom.xml
@@ -473,7 +473,7 @@ under the License.
${mercuryMp3Version}
- org.sonatype.plexus
+ org.codehaus.plexusplexus-sec-dispatcher${securityDispatcherVersion}
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index e0b647902053..fc90bbc13493 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -131,7 +131,7 @@ under the License.
org.eclipse.sisu.plexus
- org.sonatype.plexus
+ org.codehaus.plexusplexus-sec-dispatcher
diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml
index a85c8a8c1191..dd0c09bb9ce8 100644
--- a/maven-settings-builder/pom.xml
+++ b/maven-settings-builder/pom.xml
@@ -62,7 +62,7 @@ under the License.
maven-settings
- org.sonatype.plexus
+ org.codehaus.plexusplexus-sec-dispatcher
diff --git a/pom.xml b/pom.xml
index 4a4f69ba3f0a..40a7ee81ade0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,8 +61,8 @@ under the License.
0.3.43.4.31.12.1
- 1.4
- 1.8
+ 2.0
+ 2.01.111.31.6.3
@@ -402,15 +402,9 @@ under the License.
${commonsLangVersion}
- org.sonatype.plexus
+ org.codehaus.plexusplexus-sec-dispatcher${securityDispatcherVersion}
-
-
- org.sonatype.plexus
- plexus-cipher
-
- org.codehaus.plexus
@@ -641,15 +635,16 @@ under the License.
enforcevalidate
- ensure-no-org.sonatype:plexus-cipher
+ ensure-no-sonatype-cipher-and-sec-dispatcher
+ org.sonatype.plexus:plexus-sec-dispatcherorg.sonatype.plexus:plexus-cipher
- ensure no more org.sonatype.plexus:plexus-cipher as groupId changed. you have to add some exclusions.
+ ensure no more org.sonatype.plexus:plexus-cipher and org.sonatype.plexus:plexus-sec-dispatcher.
From 383cabf9e4992eeff36c9b5731d95bafa72398d3 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Mon, 16 Aug 2021 18:08:39 +0200
Subject: [PATCH 079/188] [MNG-7216] [Regression] Revert MNG-7170
This reverts commit 5a8997312680a4b9c69a129801524691bc546c08.
This closes #524
---
.../maven/project/ProjectBuilderTest.java | 26 -------------------
.../projects/modelsourcebasedir/pom.xml | 19 --------------
.../model/building/DefaultModelBuilder.java | 9 +------
3 files changed, 1 insertion(+), 53 deletions(-)
delete mode 100644 maven-core/src/test/resources/projects/modelsourcebasedir/pom.xml
diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java
index 37d51cd49d00..6adb10e8f4e2 100644
--- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java
@@ -39,8 +39,6 @@
import org.apache.maven.model.Plugin;
import org.apache.maven.model.building.FileModelSource;
import org.apache.maven.model.building.ModelBuildingRequest;
-import org.apache.maven.model.building.ModelProblem;
-import org.apache.maven.model.building.ModelProblem.Severity;
import org.apache.maven.model.building.ModelSource;
import org.apache.maven.shared.utils.io.FileUtils;
@@ -85,30 +83,6 @@ public void testBuildFromModelSource()
assertNotNull( result.getProject().getParentFile() );
}
- public void testBuildFromModelSourceResolvesBasedir()
- throws Exception
- {
- File pomFile = new File( "src/test/resources/projects/modelsourcebasedir/pom.xml" );
- MavenSession mavenSession = createMavenSession( null );
- ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
- configuration.setRepositorySession( mavenSession.getRepositorySession() );
- ModelSource modelSource = new FileModelSource( pomFile );
- ProjectBuildingResult result =
- getContainer().lookup( org.apache.maven.project.ProjectBuilder.class ).build( modelSource, configuration );
-
- assertEquals( pomFile.getAbsoluteFile(), result.getProject().getModel().getPomFile().getAbsoluteFile() );
- int errors = 0;
- for ( ModelProblem p : result.getProblems() )
- {
- if ( p.getSeverity() == Severity.ERROR )
- {
- errors++;
- }
- }
- assertEquals( 0, errors );
- }
-
-
public void testVersionlessManagedDependency()
throws Exception
{
diff --git a/maven-core/src/test/resources/projects/modelsourcebasedir/pom.xml b/maven-core/src/test/resources/projects/modelsourcebasedir/pom.xml
deleted file mode 100644
index ec0f7d385a9b..000000000000
--- a/maven-core/src/test/resources/projects/modelsourcebasedir/pom.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
- 4.0.0
- test.readparent
- local-parent
- pom
- 1.0
-
-
-
- blah
- blah
- 0.0.1-SNASPSHOT
- system
- ${basedir}/blah.jar
-
-
-
-
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
index a089f9d991df..70c9ed529cd2 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
@@ -624,14 +624,7 @@ private Model readModel( ModelSource modelSource, File pomFile, ModelBuildingReq
throw problems.newModelBuildingException();
}
- if ( pomFile != null )
- {
- model.setPomFile( pomFile );
- }
- else if ( modelSource instanceof FileModelSource )
- {
- model.setPomFile( ( (FileModelSource) modelSource ).getFile() );
- }
+ model.setPomFile( pomFile );
problems.setSource( model );
modelValidator.validateRawModel( model, request, problems );
From e08834b79e9387811ece442f6e7b445b19110fcf Mon Sep 17 00:00:00 2001
From: Tamas Cservenak
Date: Mon, 13 Sep 2021 17:56:54 +0200
Subject: [PATCH 080/188] [MNG-7250] Upgrade Sisu Inject/Plexus to 0.3.5
Since we have replaced the old JSR 250 library with javax.annotation library we
go straight to 1.2.
This closes #539
---
.../appended-resources/META-INF/LICENSE.vm | 6 +-
.../appended-resources/META-INF/NOTICE.vm | 2 +-
.../appended-resources/licenses/CDDL-1.0.txt | 384 ---------
.../unrecognized-javax.annotation-api-1.2.txt | 759 ++++++++++++++++++
.../resources/META-INF/maven/extension.xml | 2 +-
maven-embedder/pom.xml | 2 +-
pom.xml | 16 +-
7 files changed, 772 insertions(+), 399 deletions(-)
delete mode 100644 apache-maven/src/main/appended-resources/licenses/CDDL-1.0.txt
create mode 100644 apache-maven/src/main/appended-resources/licenses/unrecognized-javax.annotation-api-1.2.txt
diff --git a/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm b/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
index 43357d142ef0..b589e36e0222 100644
--- a/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
+++ b/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
@@ -33,9 +33,7 @@ subject to the terms and conditions of the following licenses:
#* *### advertise about each non-Maven dependency
#* *###
#* *### infer SPDX license id
-#* *##if ( $license.name == "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0" )
-#* *##set ( $spdx = 'CDDL-1.0' )
-#* *##elseif ( $MITLicenseNames.contains( $license.name ) )
+#* *##if ( $MITLicenseNames.contains( $license.name ) )
#* *##set ( $spdx = 'MIT' )
#* *##elseif ( $license.name == "Eclipse Public License, Version 1.0" )
#* *##set ( $spdx = 'EPL-1.0' )
@@ -62,7 +60,7 @@ subject to the terms and conditions of the following licenses:
#* *###
#* *### copy license file to lib/$artifactId.license
#* *##set ( $licFile = $directory + '/' + $project.artifact.artifactId + '.license' )
-#* *##if ( $spdx == "MIT" )
+#* *##if ( $spdx == "MIT" || $spdx == "unrecognized" )
#* *### MIT license contains date and copyright that makes the file specific to each artifact
#* *##set ( $downloaded = $locator.getResourceAsFile( "licenses/${spdx}-${project.artifact.artifactId}-${project.artifact.version}.txt", "licenses/${licFile}" ) )
#* *##else
diff --git a/apache-maven/src/main/appended-resources/META-INF/NOTICE.vm b/apache-maven/src/main/appended-resources/META-INF/NOTICE.vm
index acf7ba42e070..3cfd92583cd2 100644
--- a/apache-maven/src/main/appended-resources/META-INF/NOTICE.vm
+++ b/apache-maven/src/main/appended-resources/META-INF/NOTICE.vm
@@ -36,7 +36,7 @@ javolution (http://javolution.org/).
This product includes software developed by
Rome (https://rome.dev.java.net/).
-about.html in archive lib/org.eclipse.sisu.inject-0.3.4.jar
+about.html in archive lib/org.eclipse.sisu.inject-0.3.5.jar
diff --git a/apache-maven/src/main/appended-resources/licenses/CDDL-1.0.txt b/apache-maven/src/main/appended-resources/licenses/CDDL-1.0.txt
deleted file mode 100644
index 9bc6342e22c9..000000000000
--- a/apache-maven/src/main/appended-resources/licenses/CDDL-1.0.txt
+++ /dev/null
@@ -1,384 +0,0 @@
-COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
-
-
- 1. Definitions.
-
- 1.1. "Contributor" means each individual or entity that
- creates or contributes to the creation of Modifications.
-
- 1.2. "Contributor Version" means the combination of the
- Original Software, prior Modifications used by a
- Contributor (if any), and the Modifications made by that
- particular Contributor.
-
- 1.3. "Covered Software" means (a) the Original Software, or
- (b) Modifications, or (c) the combination of files
- containing Original Software with files containing
- Modifications, in each case including portions thereof.
-
- 1.4. "Executable" means the Covered Software in any form
- other than Source Code.
-
- 1.5. "Initial Developer" means the individual or entity
- that first makes Original Software available under this
- License.
-
- 1.6. "Larger Work" means a work which combines Covered
- Software or portions thereof with code not governed by the
- terms of this License.
-
- 1.7. "License" means this document.
-
- 1.8. "Licensable" means having the right to grant, to the
- maximum extent possible, whether at the time of the initial
- grant or subsequently acquired, any and all of the rights
- conveyed herein.
-
- 1.9. "Modifications" means the Source Code and Executable
- form of any of the following:
-
- A. Any file that results from an addition to,
- deletion from or modification of the contents of a
- file containing Original Software or previous
- Modifications;
-
- B. Any new file that contains any part of the
- Original Software or previous Modification; or
-
- C. Any new file that is contributed or otherwise made
- available under the terms of this License.
-
- 1.10. "Original Software" means the Source Code and
- Executable form of computer software code that is
- originally released under this License.
-
- 1.11. "Patent Claims" means any patent claim(s), now owned
- or hereafter acquired, including without limitation,
- method, process, and apparatus claims, in any patent
- Licensable by grantor.
-
- 1.12. "Source Code" means (a) the common form of computer
- software code in which modifications are made and (b)
- associated documentation included in or with such code.
-
- 1.13. "You" (or "Your") means an individual or a legal
- entity exercising rights under, and complying with all of
- the terms of, this License. For legal entities, "You"
- includes any entity which controls, is controlled by, or is
- under common control with You. For purposes of this
- definition, "control" means (a) the power, direct or
- indirect, to cause the direction or management of such
- entity, whether by contract or otherwise, or (b) ownership
- of more than fifty percent (50%) of the outstanding shares
- or beneficial ownership of such entity.
-
- 2. License Grants.
-
- 2.1. The Initial Developer Grant.
-
- Conditioned upon Your compliance with Section 3.1 below and
- subject to third party intellectual property claims, the
- Initial Developer hereby grants You a world-wide,
- royalty-free, non-exclusive license:
-
- (a) under intellectual property rights (other than
- patent or trademark) Licensable by Initial Developer,
- to use, reproduce, modify, display, perform,
- sublicense and distribute the Original Software (or
- portions thereof), with or without Modifications,
- and/or as part of a Larger Work; and
-
- (b) under Patent Claims infringed by the making,
- using or selling of Original Software, to make, have
- made, use, practice, sell, and offer for sale, and/or
- otherwise dispose of the Original Software (or
- portions thereof).
-
- (c) The licenses granted in Sections 2.1(a) and (b)
- are effective on the date Initial Developer first
- distributes or otherwise makes the Original Software
- available to a third party under the terms of this
- License.
-
- (d) Notwithstanding Section 2.1(b) above, no patent
- license is granted: (1) for code that You delete from
- the Original Software, or (2) for infringements
- caused by: (i) the modification of the Original
- Software, or (ii) the combination of the Original
- Software with other software or devices.
-
- 2.2. Contributor Grant.
-
- Conditioned upon Your compliance with Section 3.1 below and
- subject to third party intellectual property claims, each
- Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- (a) under intellectual property rights (other than
- patent or trademark) Licensable by Contributor to
- use, reproduce, modify, display, perform, sublicense
- and distribute the Modifications created by such
- Contributor (or portions thereof), either on an
- unmodified basis, with other Modifications, as
- Covered Software and/or as part of a Larger Work; and
-
-
- (b) under Patent Claims infringed by the making,
- using, or selling of Modifications made by that
- Contributor either alone and/or in combination with
- its Contributor Version (or portions of such
- combination), to make, use, sell, offer for sale,
- have made, and/or otherwise dispose of: (1)
- Modifications made by that Contributor (or portions
- thereof); and (2) the combination of Modifications
- made by that Contributor with its Contributor Version
- (or portions of such combination).
-
- (c) The licenses granted in Sections 2.2(a) and
- 2.2(b) are effective on the date Contributor first
- distributes or otherwise makes the Modifications
- available to a third party.
-
- (d) Notwithstanding Section 2.2(b) above, no patent
- license is granted: (1) for any code that Contributor
- has deleted from the Contributor Version; (2) for
- infringements caused by: (i) third party
- modifications of Contributor Version, or (ii) the
- combination of Modifications made by that Contributor
- with other software (except as part of the
- Contributor Version) or other devices; or (3) under
- Patent Claims infringed by Covered Software in the
- absence of Modifications made by that Contributor.
-
- 3. Distribution Obligations.
-
- 3.1. Availability of Source Code.
-
- Any Covered Software that You distribute or otherwise make
- available in Executable form must also be made available in
- Source Code form and that Source Code form must be
- distributed only under the terms of this License. You must
- include a copy of this License with every copy of the
- Source Code form of the Covered Software You distribute or
- otherwise make available. You must inform recipients of any
- such Covered Software in Executable form as to how they can
- obtain such Covered Software in Source Code form in a
- reasonable manner on or through a medium customarily used
- for software exchange.
-
- 3.2. Modifications.
-
- The Modifications that You create or to which You
- contribute are governed by the terms of this License. You
- represent that You believe Your Modifications are Your
- original creation(s) and/or You have sufficient rights to
- grant the rights conveyed by this License.
-
- 3.3. Required Notices.
-
- You must include a notice in each of Your Modifications
- that identifies You as the Contributor of the Modification.
- You may not remove or alter any copyright, patent or
- trademark notices contained within the Covered Software, or
- any notices of licensing or any descriptive text giving
- attribution to any Contributor or the Initial Developer.
-
- 3.4. Application of Additional Terms.
-
- You may not offer or impose any terms on any Covered
- Software in Source Code form that alters or restricts the
- applicable version of this License or the recipients"
- rights hereunder. You may choose to offer, and to charge a
- fee for, warranty, support, indemnity or liability
- obligations to one or more recipients of Covered Software.
- However, you may do so only on Your own behalf, and not on
- behalf of the Initial Developer or any Contributor. You
- must make it absolutely clear that any such warranty,
- support, indemnity or liability obligation is offered by
- You alone, and You hereby agree to indemnify the Initial
- Developer and every Contributor for any liability incurred
- by the Initial Developer or such Contributor as a result of
- warranty, support, indemnity or liability terms You offer.
-
-
- 3.5. Distribution of Executable Versions.
-
- You may distribute the Executable form of the Covered
- Software under the terms of this License or under the terms
- of a license of Your choice, which may contain terms
- different from this License, provided that You are in
- compliance with the terms of this License and that the
- license for the Executable form does not attempt to limit
- or alter the recipient"s rights in the Source Code form
- from the rights set forth in this License. If You
- distribute the Covered Software in Executable form under a
- different license, You must make it absolutely clear that
- any terms which differ from this License are offered by You
- alone, not by the Initial Developer or Contributor. You
- hereby agree to indemnify the Initial Developer and every
- Contributor for any liability incurred by the Initial
- Developer or such Contributor as a result of any such terms
- You offer.
-
- 3.6. Larger Works.
-
- You may create a Larger Work by combining Covered Software
- with other code not governed by the terms of this License
- and distribute the Larger Work as a single product. In such
- a case, You must make sure the requirements of this License
- are fulfilled for the Covered Software.
-
- 4. Versions of the License.
-
- 4.1. New Versions.
-
- Sun Microsystems, Inc. is the initial license steward and
- may publish revised and/or new versions of this License
- from time to time. Each version will be given a
- distinguishing version number. Except as provided in
- Section 4.3, no one other than the license steward has the
- right to modify this License.
-
- 4.2. Effect of New Versions.
-
- You may always continue to use, distribute or otherwise
- make the Covered Software available under the terms of the
- version of the License under which You originally received
- the Covered Software. If the Initial Developer includes a
- notice in the Original Software prohibiting it from being
- distributed or otherwise made available under any
- subsequent version of the License, You must distribute and
- make the Covered Software available under the terms of the
- version of the License under which You originally received
- the Covered Software. Otherwise, You may also choose to
- use, distribute or otherwise make the Covered Software
- available under the terms of any subsequent version of the
- License published by the license steward.
-
- 4.3. Modified Versions.
-
- When You are an Initial Developer and You want to create a
- new license for Your Original Software, You may create and
- use a modified version of this License if You: (a) rename
- the license and remove any references to the name of the
- license steward (except to note that the license differs
- from this License); and (b) otherwise make it clear that
- the license contains terms which differ from this License.
-
-
- 5. DISCLAIMER OF WARRANTY.
-
- COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
- BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
- INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
- SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
- PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
- PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY
- COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
- INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF
- ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
- WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
- ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
- DISCLAIMER.
-
- 6. TERMINATION.
-
- 6.1. This License and the rights granted hereunder will
- terminate automatically if You fail to comply with terms
- herein and fail to cure such breach within 30 days of
- becoming aware of the breach. Provisions which, by their
- nature, must remain in effect beyond the termination of
- this License shall survive.
-
- 6.2. If You assert a patent infringement claim (excluding
- declaratory judgment actions) against Initial Developer or
- a Contributor (the Initial Developer or Contributor against
- whom You assert such claim is referred to as "Participant")
- alleging that the Participant Software (meaning the
- Contributor Version where the Participant is a Contributor
- or the Original Software where the Participant is the
- Initial Developer) directly or indirectly infringes any
- patent, then any and all rights granted directly or
- indirectly to You by such Participant, the Initial
- Developer (if the Initial Developer is not the Participant)
- and all Contributors under Sections 2.1 and/or 2.2 of this
- License shall, upon 60 days notice from Participant
- terminate prospectively and automatically at the expiration
- of such 60 day notice period, unless if within such 60 day
- period You withdraw Your claim with respect to the
- Participant Software against such Participant either
- unilaterally or pursuant to a written agreement with
- Participant.
-
- 6.3. In the event of termination under Sections 6.1 or 6.2
- above, all end user licenses that have been validly granted
- by You or any distributor hereunder prior to termination
- (excluding licenses granted to You by any distributor)
- shall survive termination.
-
- 7. LIMITATION OF LIABILITY.
-
- UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
- (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
- INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
- COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
- LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
- CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
- LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
- STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
- COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
- INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
- LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
- INJURY RESULTING FROM SUCH PARTY"S NEGLIGENCE TO THE EXTENT
- APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO
- NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
- CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
- APPLY TO YOU.
-
- 8. U.S. GOVERNMENT END USERS.
-
- The Covered Software is a "commercial item," as that term is
- defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
- computer software" (as that term is defined at 48 C.F.R. "
- 252.227-7014(a)(1)) and "commercial computer software
- documentation" as such terms are used in 48 C.F.R. 12.212 (Sept.
- 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1
- through 227.7202-4 (June 1995), all U.S. Government End Users
- acquire Covered Software with only those rights set forth herein.
- This U.S. Government Rights clause is in lieu of, and supersedes,
- any other FAR, DFAR, or other clause or provision that addresses
- Government rights in computer software under this License.
-
- 9. MISCELLANEOUS.
-
- This License represents the complete agreement concerning subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the
- extent necessary to make it enforceable. This License shall be
- governed by the law of the jurisdiction specified in a notice
- contained within the Original Software (except to the extent
- applicable law, if any, provides otherwise), excluding such
- jurisdiction"s conflict-of-law provisions. Any litigation
- relating to this License shall be subject to the jurisdiction of
- the courts located in the jurisdiction and venue specified in a
- notice contained within the Original Software, with the losing
- party responsible for costs, including, without limitation, court
- costs and reasonable attorneys" fees and expenses. The
- application of the United Nations Convention on Contracts for the
- International Sale of Goods is expressly excluded. Any law or
- regulation which provides that the language of a contract shall
- be construed against the drafter shall not apply to this License.
- You agree that You alone are responsible for compliance with the
- United States export administration regulations (and the export
- control laws and regulation of any other countries) when You use,
- distribute or otherwise make available any Covered Software.
-
- 10. RESPONSIBILITY FOR CLAIMS.
-
- As between Initial Developer and the Contributors, each party is
- responsible for claims and damages arising, directly or
- indirectly, out of its utilization of rights under this License
- and You agree to work with Initial Developer and Contributors to
- distribute such responsibility on an equitable basis. Nothing
- herein is intended or shall be deemed to constitute any admission
- of liability.
diff --git a/apache-maven/src/main/appended-resources/licenses/unrecognized-javax.annotation-api-1.2.txt b/apache-maven/src/main/appended-resources/licenses/unrecognized-javax.annotation-api-1.2.txt
new file mode 100644
index 000000000000..b1c74f95ede8
--- /dev/null
+++ b/apache-maven/src/main/appended-resources/licenses/unrecognized-javax.annotation-api-1.2.txt
@@ -0,0 +1,759 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1
+
+1. Definitions.
+
+ 1.1. "Contributor" means each individual or entity that creates or
+ contributes to the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the Original
+ Software, prior Modifications used by a Contributor (if any), and
+ the Modifications made by that particular Contributor.
+
+ 1.3. "Covered Software" means (a) the Original Software, or (b)
+ Modifications, or (c) the combination of files containing Original
+ Software with files containing Modifications, in each case including
+ portions thereof.
+
+ 1.4. "Executable" means the Covered Software in any form other than
+ Source Code.
+
+ 1.5. "Initial Developer" means the individual or entity that first
+ makes Original Software available under this License.
+
+ 1.6. "Larger Work" means a work which combines Covered Software or
+ portions thereof with code not governed by the terms of this License.
+
+ 1.7. "License" means this document.
+
+ 1.8. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. "Modifications" means the Source Code and Executable form of
+ any of the following:
+
+ A. Any file that results from an addition to, deletion from or
+ modification of the contents of a file containing Original Software
+ or previous Modifications;
+
+ B. Any new file that contains any part of the Original Software or
+ previous Modification; or
+
+ C. Any new file that is contributed or otherwise made available
+ under the terms of this License.
+
+ 1.10. "Original Software" means the Source Code and Executable form
+ of computer software code that is originally released under this
+ License.
+
+ 1.11. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by grantor.
+
+ 1.12. "Source Code" means (a) the common form of computer software
+ code in which modifications are made and (b) associated
+ documentation included in or with such code.
+
+ 1.13. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms of,
+ this License. For legal entities, "You" includes any entity which
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants.
+
+ 2.1. The Initial Developer Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and subject
+ to third party intellectual property claims, the Initial Developer
+ hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer, to use, reproduce,
+ modify, display, perform, sublicense and distribute the Original
+ Software (or portions thereof), with or without Modifications,
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using or selling of
+ Original Software, to make, have made, use, practice, sell, and
+ offer for sale, and/or otherwise dispose of the Original Software
+ (or portions thereof).
+
+ (c) The licenses granted in Sections 2.1(a) and (b) are effective on
+ the date Initial Developer first distributes or otherwise makes the
+ Original Software available to a third party under the terms of this
+ License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: (1) for code that You delete from the Original Software, or
+ (2) for infringements caused by: (i) the modification of the
+ Original Software, or (ii) the combination of the Original Software
+ with other software or devices.
+
+ 2.2. Contributor Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and subject
+ to third party intellectual property claims, each Contributor hereby
+ grants You a world-wide, royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor to use, reproduce, modify,
+ display, perform, sublicense and distribute the Modifications
+ created by such Contributor (or portions thereof), either on an
+ unmodified basis, with other Modifications, as Covered Software
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or selling
+ of Modifications made by that Contributor either alone and/or in
+ combination with its Contributor Version (or portions of such
+ combination), to make, use, sell, offer for sale, have made, and/or
+ otherwise dispose of: (1) Modifications made by that Contributor (or
+ portions thereof); and (2) the combination of Modifications made by
+ that Contributor with its Contributor Version (or portions of such
+ combination).
+
+ (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective
+ on the date Contributor first distributes or otherwise makes the
+ Modifications available to a third party.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: (1) for any code that Contributor has deleted from the
+ Contributor Version; (2) for infringements caused by: (i) third
+ party modifications of Contributor Version, or (ii) the combination
+ of Modifications made by that Contributor with other software
+ (except as part of the Contributor Version) or other devices; or (3)
+ under Patent Claims infringed by Covered Software in the absence of
+ Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Availability of Source Code.
+
+ Any Covered Software that You distribute or otherwise make available
+ in Executable form must also be made available in Source Code form
+ and that Source Code form must be distributed only under the terms
+ of this License. You must include a copy of this License with every
+ copy of the Source Code form of the Covered Software You distribute
+ or otherwise make available. You must inform recipients of any such
+ Covered Software in Executable form as to how they can obtain such
+ Covered Software in Source Code form in a reasonable manner on or
+ through a medium customarily used for software exchange.
+
+ 3.2. Modifications.
+
+ The Modifications that You create or to which You contribute are
+ governed by the terms of this License. You represent that You
+ believe Your Modifications are Your original creation(s) and/or You
+ have sufficient rights to grant the rights conveyed by this License.
+
+ 3.3. Required Notices.
+
+ You must include a notice in each of Your Modifications that
+ identifies You as the Contributor of the Modification. You may not
+ remove or alter any copyright, patent or trademark notices contained
+ within the Covered Software, or any notices of licensing or any
+ descriptive text giving attribution to any Contributor or the
+ Initial Developer.
+
+ 3.4. Application of Additional Terms.
+
+ You may not offer or impose any terms on any Covered Software in
+ Source Code form that alters or restricts the applicable version of
+ this License or the recipients' rights hereunder. You may choose to
+ offer, and to charge a fee for, warranty, support, indemnity or
+ liability obligations to one or more recipients of Covered Software.
+ However, you may do so only on Your own behalf, and not on behalf of
+ the Initial Developer or any Contributor. You must make it
+ absolutely clear that any such warranty, support, indemnity or
+ liability obligation is offered by You alone, and You hereby agree
+ to indemnify the Initial Developer and every Contributor for any
+ liability incurred by the Initial Developer or such Contributor as a
+ result of warranty, support, indemnity or liability terms You offer.
+
+ 3.5. Distribution of Executable Versions.
+
+ You may distribute the Executable form of the Covered Software under
+ the terms of this License or under the terms of a license of Your
+ choice, which may contain terms different from this License,
+ provided that You are in compliance with the terms of this License
+ and that the license for the Executable form does not attempt to
+ limit or alter the recipient's rights in the Source Code form from
+ the rights set forth in this License. If You distribute the Covered
+ Software in Executable form under a different license, You must make
+ it absolutely clear that any terms which differ from this License
+ are offered by You alone, not by the Initial Developer or
+ Contributor. You hereby agree to indemnify the Initial Developer and
+ every Contributor for any liability incurred by the Initial
+ Developer or such Contributor as a result of any such terms You offer.
+
+ 3.6. Larger Works.
+
+ You may create a Larger Work by combining Covered Software with
+ other code not governed by the terms of this License and distribute
+ the Larger Work as a single product. In such a case, You must make
+ sure the requirements of this License are fulfilled for the Covered
+ Software.
+
+4. Versions of the License.
+
+ 4.1. New Versions.
+
+ Oracle is the initial license steward and may publish revised and/or
+ new versions of this License from time to time. Each version will be
+ given a distinguishing version number. Except as provided in Section
+ 4.3, no one other than the license steward has the right to modify
+ this License.
+
+ 4.2. Effect of New Versions.
+
+ You may always continue to use, distribute or otherwise make the
+ Covered Software available under the terms of the version of the
+ License under which You originally received the Covered Software. If
+ the Initial Developer includes a notice in the Original Software
+ prohibiting it from being distributed or otherwise made available
+ under any subsequent version of the License, You must distribute and
+ make the Covered Software available under the terms of the version
+ of the License under which You originally received the Covered
+ Software. Otherwise, You may also choose to use, distribute or
+ otherwise make the Covered Software available under the terms of any
+ subsequent version of the License published by the license steward.
+
+ 4.3. Modified Versions.
+
+ When You are an Initial Developer and You want to create a new
+ license for Your Original Software, You may create and use a
+ modified version of this License if You: (a) rename the license and
+ remove any references to the name of the license steward (except to
+ note that the license differs from this License); and (b) otherwise
+ make it clear that the license contains terms which differ from this
+ License.
+
+5. DISCLAIMER OF WARRANTY.
+
+ COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+ INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE
+ IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR
+ NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF
+ THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE
+ DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY
+ OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING,
+ REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
+ ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS
+ AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+ 6.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to
+ cure such breach within 30 days of becoming aware of the breach.
+ Provisions which, by their nature, must remain in effect beyond the
+ termination of this License shall survive.
+
+ 6.2. If You assert a patent infringement claim (excluding
+ declaratory judgment actions) against Initial Developer or a
+ Contributor (the Initial Developer or Contributor against whom You
+ assert such claim is referred to as "Participant") alleging that the
+ Participant Software (meaning the Contributor Version where the
+ Participant is a Contributor or the Original Software where the
+ Participant is the Initial Developer) directly or indirectly
+ infringes any patent, then any and all rights granted directly or
+ indirectly to You by such Participant, the Initial Developer (if the
+ Initial Developer is not the Participant) and all Contributors under
+ Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice
+ from Participant terminate prospectively and automatically at the
+ expiration of such 60 day notice period, unless if within such 60
+ day period You withdraw Your claim with respect to the Participant
+ Software against such Participant either unilaterally or pursuant to
+ a written agreement with Participant.
+
+ 6.3. If You assert a patent infringement claim against Participant
+ alleging that the Participant Software directly or indirectly
+ infringes any patent where such claim is resolved (such as by
+ license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+
+ 6.4. In the event of termination under Sections 6.1 or 6.2 above,
+ all end user licenses that have been validly granted by You or any
+ distributor hereunder prior to termination (excluding licenses
+ granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+ INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+ COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE
+ TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+ CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+ LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER
+ FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR
+ LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE
+ POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT
+ APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH
+ PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH
+ LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR
+ LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION
+ AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+ The Covered Software is a "commercial item," as that term is defined
+ in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" (as that term is defined at 48 C.F.R. §
+ 252.227-7014(a)(1)) and "commercial computer software documentation"
+ as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent
+ with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4
+ (June 1995), all U.S. Government End Users acquire Covered Software
+ with only those rights set forth herein. This U.S. Government Rights
+ clause is in lieu of, and supersedes, any other FAR, DFAR, or other
+ clause or provision that addresses Government rights in computer
+ software under this License.
+
+9. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ the law of the jurisdiction specified in a notice contained within
+ the Original Software (except to the extent applicable law, if any,
+ provides otherwise), excluding such jurisdiction's conflict-of-law
+ provisions. Any litigation relating to this License shall be subject
+ to the jurisdiction of the courts located in the jurisdiction and
+ venue specified in a notice contained within the Original Software,
+ with the losing party responsible for costs, including, without
+ limitation, court costs and reasonable attorneys' fees and expenses.
+ The application of the United Nations Convention on Contracts for
+ the International Sale of Goods is expressly excluded. Any law or
+ regulation which provides that the language of a contract shall be
+ construed against the drafter shall not apply to this License. You
+ agree that You alone are responsible for compliance with the United
+ States export administration regulations (and the export control
+ laws and regulation of any other countries) when You use, distribute
+ or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+
+------------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION
+LICENSE (CDDL)
+
+The code released under the CDDL shall be governed by the laws of the
+State of California (excluding conflict-of-law provisions). Any
+litigation relating to this License shall be subject to the jurisdiction
+of the Federal Courts of the Northern District of California and the
+state courts of the State of California, with venue lying in Santa Clara
+County, California.
+
+
+
+ The GNU General Public License (GPL) Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor
+Boston, MA 02110-1335
+USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public License is
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users. This General Public
+License applies to most of the Free Software Foundation's software and
+to any other program whose authors commit to using it. (Some other Free
+Software Foundation software is covered by the GNU Library General
+Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price.
+Our General Public Licenses are designed to make sure that you have the
+freedom to distribute copies of free software (and charge for this
+service if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone
+to deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis
+or for a fee, you must give the recipients all the rights that you have.
+You must make sure that they, too, receive or can get the source code.
+And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+Finally, any free program is threatened constantly by software patents.
+We wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program
+proprietary. To prevent this, we have made it clear that any patent must
+be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a
+notice placed by the copyright holder saying it may be distributed under
+the terms of this General Public License. The "Program", below, refers
+to any such program or work, and a "work based on the Program" means
+either the Program or any derivative work under copyright law: that is
+to say, a work containing the Program or a portion of it, either
+verbatim or with modifications and/or translated into another language.
+(Hereinafter, translation is included without limitation in the term
+"modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of running
+the Program is not restricted, and the output from the Program is
+covered only if its contents constitute a work based on the Program
+(independent of having been made by running the Program). Whether that
+is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy an appropriate copyright notice
+and disclaimer of warranty; keep intact all the notices that refer to
+this License and to the absence of any warranty; and give any other
+recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of
+it, thus forming a work based on the Program, and copy and distribute
+such modifications or work under the terms of Section 1 above, provided
+that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any part
+ thereof, to be licensed as a whole at no charge to all third parties
+ under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a notice
+ that there is no warranty (or else, saying that you provide a
+ warranty) and that users may redistribute the program under these
+ conditions, and telling the user how to view a copy of this License.
+ (Exception: if the Program itself is interactive but does not
+ normally print such an announcement, your work based on the Program
+ is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program, and
+can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based on
+the Program, the distribution of the whole must be on the terms of this
+License, whose permissions for other licensees extend to the entire
+whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of a
+storage or distribution medium does not bring the other work under the
+scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections 1
+ and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your cost
+ of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer to
+ distribute corresponding source code. (This alternative is allowed
+ only for noncommercial distribution and only if you received the
+ program in object code or executable form with such an offer, in
+ accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source code
+means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to control
+compilation and installation of the executable. However, as a special
+exception, the source code distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies the
+executable.
+
+If distribution of executable or object code is made by offering access
+to copy from a designated place, then offering equivalent access to copy
+the source code from the same place counts as distribution of the source
+code, even though third parties are not compelled to copy the source
+along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt otherwise
+to copy, modify, sublicense or distribute the Program is void, and will
+automatically terminate your rights under this License. However, parties
+who have received copies, or rights, from you under this License will
+not have their licenses terminated so long as such parties remain in
+full compliance.
+
+5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and all
+its terms and conditions for copying, distributing or modifying the
+Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further restrictions
+on the recipients' exercise of the rights granted herein. You are not
+responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot distribute
+so as to satisfy simultaneously your obligations under this License and
+any other pertinent obligations, then as a consequence you may not
+distribute the Program at all. For example, if a patent license would
+not permit royalty-free redistribution of the Program by all those who
+receive copies directly or indirectly through you, then the only way you
+could satisfy both it and this License would be to refrain entirely from
+distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is implemented
+by public license practices. Many people have made generous
+contributions to the wide range of software distributed through that
+system in reliance on consistent application of that system; it is up to
+the author/donor to decide if he or she is willing to distribute
+software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be
+a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License may
+add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among countries
+not thus excluded. In such case, this License incorporates the
+limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new
+versions of the General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Program does not specify a version
+number of this License, you may choose any version ever published by the
+Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the
+author to ask for permission. For software which is copyrighted by the
+Free Software Foundation, write to the Free Software Foundation; we
+sometimes make exceptions for this. Our decision will be guided by the
+two goals of preserving the free status of all derivatives of our free
+software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH
+YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
+(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
+THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR
+OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ One line to give the program's name and a brief idea of what it does.
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type
+ `show w'. This is free software, and you are welcome to redistribute
+ it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License. Of course, the commands
+you use may be called something other than `show w' and `show c'; they
+could even be mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ program `Gnomovision' (which makes passes at compilers) written by
+ James Hacker.
+
+ signature of Ty Coon, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications
+with the library. If this is what you want to do, use the GNU Library
+General Public License instead of this License.
+
+#
+
+Certain source files distributed by Oracle America, Inc. and/or its
+affiliates are subject to the following clarification and special
+exception to the GPLv2, based on the GNU Project exception for its
+Classpath libraries, known as the GNU Classpath Exception, but only
+where Oracle has expressly included in the particular source file's
+header the words "Oracle designates this particular file as subject to
+the "Classpath" exception as provided by Oracle in the LICENSE file
+that accompanied this code."
+
+You should also note that Oracle includes multiple, independent
+programs in this software package. Some of those programs are provided
+under licenses deemed incompatible with the GPLv2 by the Free Software
+Foundation and others. For example, the package includes programs
+licensed under the Apache License, Version 2.0. Such programs are
+licensed to you under their original licenses.
+
+Oracle facilitates your further distribution of this package by adding
+the Classpath Exception to the necessary parts of its GPLv2 code, which
+permits you to use that code in combination with other independent
+modules not licensed under the GPLv2. However, note that this would
+not permit you to commingle code under an incompatible license with
+Oracle's GPLv2 licensed code by, for example, cutting and pasting such
+code into a file also containing Oracle's GPLv2 licensed code and then
+distributing the result. Additionally, if you were to remove the
+Classpath Exception from any of the files to which it applies and
+distribute the result, you would likely be required to license some or
+all of the other code in that distribution under the GPLv2 as well, and
+since the GPLv2 is incompatible with the license terms of some items
+included in the distribution by Oracle, removing the Classpath
+Exception could therefore effectively compromise your ability to
+further distribute the package.
+
+Proceed with caution and we recommend that you obtain the advice of a
+lawyer skilled in open source matters before removing the Classpath
+Exception or making modifications to this package which may
+subsequently be redistributed and/or involve the use of third party
+software.
+
+CLASSPATH EXCEPTION
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License version 2 cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from or
+based on this library. If you modify this library, you may extend this
+exception to your version of the library, but you are not obligated to
+do so. If you do not wish to do so, delete this exception statement
+from your version.
diff --git a/maven-core/src/main/resources/META-INF/maven/extension.xml b/maven-core/src/main/resources/META-INF/maven/extension.xml
index 6bd836927364..1fa9d41750b6 100644
--- a/maven-core/src/main/resources/META-INF/maven/extension.xml
+++ b/maven-core/src/main/resources/META-INF/maven/extension.xml
@@ -166,7 +166,7 @@ under the License.
org.apache.maven.resolver:maven-resolver-impljavax.inject:javax.inject
- javax.annotation:jsr250-api
+ javax.annotation:javax.annotation-apiorg.slf4j:slf4j-apiorg.fusesource.jansi:jansi
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index fc90bbc13493..232bb9031048 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -116,7 +116,7 @@ under the License.
javax.annotation
- jsr250-api
+ javax.annotation-apiorg.codehaus.plexus
diff --git a/pom.xml b/pom.xml
index 40a7ee81ade0..9e68774899cc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,7 +58,7 @@ under the License.
1.263.3.04.2.2
- 0.3.4
+ 0.3.53.4.31.12.12.0
@@ -248,12 +248,12 @@ under the License.
org.eclipse.sisuorg.eclipse.sisu.plexus
- ${sisuInjectVersion}
+ ${sisuVersion}org.eclipse.sisuorg.eclipse.sisu.inject
- ${sisuInjectVersion}
+ ${sisuVersion}javax.inject
@@ -262,8 +262,8 @@ under the License.
javax.annotation
- jsr250-api
- 1.0
+ javax.annotation-api
+ 1.2org.codehaus.plexus
@@ -480,7 +480,7 @@ under the License.
org.eclipse.sisusisu-maven-plugin
- ${sisuInjectVersion}
+ ${sisuVersion}
@@ -545,10 +545,10 @@ under the License.
src/test/remote-repo/****/*.odg
- src/main/appended-resources/licenses/CDDL-1.0.txtsrc/main/appended-resources/licenses/EPL-1.0.txt
+ src/main/appended-resources/licenses/unrecognized-javax.annotation-api-1.2.txt
From 4e5b3d55545e5f03f05ac7b0cd1b56689df36201 Mon Sep 17 00:00:00 2001
From: Falko Modler
Date: Sun, 22 Aug 2021 22:52:30 +0200
Subject: [PATCH 081/188] [MNG-7251] Fix threadLocalArtifactsHolder leaking
into cloned project
This closes #527
---
.../apache/maven/project/MavenProject.java | 49 ++++++++++---------
.../maven/project/MavenProjectTest.java | 43 ++++++++++++++++
2 files changed, 68 insertions(+), 24 deletions(-)
diff --git a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
index 157b7a0f0a55..94d678814534 100644
--- a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
+++ b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
@@ -143,13 +143,7 @@ public class MavenProject
private Artifact artifact;
- private final ThreadLocal threadLocalArtifactsHolder = new ThreadLocal()
- {
- protected ArtifactsHolder initialValue()
- {
- return new ArtifactsHolder();
- }
- };
+ private ThreadLocal threadLocalArtifactsHolder = newThreadLocalArtifactsHolder();
private Model originalModel;
@@ -188,6 +182,17 @@ public MavenProject()
setModel( model );
}
+ private static ThreadLocal newThreadLocalArtifactsHolder()
+ {
+ return new ThreadLocal()
+ {
+ protected ArtifactsHolder initialValue()
+ {
+ return new ArtifactsHolder();
+ }
+ };
+ }
+
public MavenProject( Model model )
{
setModel( model );
@@ -1181,7 +1186,8 @@ public MavenProject clone()
{
throw new UnsupportedOperationException( e );
}
-
+ // clone must have it's own TL, otherwise the artifacts are intermingled!
+ clone.threadLocalArtifactsHolder = newThreadLocalArtifactsHolder();
clone.deepCopy( this );
return clone;
@@ -1224,6 +1230,7 @@ private void deepCopy( MavenProject project )
// copy fields
file = project.file;
basedir = project.basedir;
+ threadLocalArtifactsHolder.set( project.threadLocalArtifactsHolder.get().copy() );
// don't need a deep copy, they don't get modified or added/removed to/from - but make them unmodifiable to be
// sure!
@@ -1232,11 +1239,6 @@ private void deepCopy( MavenProject project )
setDependencyArtifacts( Collections.unmodifiableSet( project.getDependencyArtifacts() ) );
}
- if ( project.getArtifacts() != null )
- {
- setArtifacts( Collections.unmodifiableSet( project.getArtifacts() ) );
- }
-
if ( project.getParentFile() != null )
{
parentFile = new File( project.getParentFile().getAbsolutePath() );
@@ -1479,13 +1481,7 @@ public void addLifecyclePhase( String lifecyclePhase )
// ----------------------------------------------------------------------------------------------------------------
//
- //
- // D E P R E C A T E D
- //
- //
- // ----------------------------------------------------------------------------------------------------------------
- //
- // Everything below will be removed for Maven 4.0.0
+ // D E P R E C A T E D - Everything below will be removed for Maven 4.0.0
//
// ----------------------------------------------------------------------------------------------------------------
@@ -1506,7 +1502,6 @@ public String getModulePathAdjustment( MavenProject moduleProject )
if ( moduleFile != null )
{
File moduleDir = moduleFile.getCanonicalFile().getParentFile();
-
module = moduleDir.getName();
}
@@ -1827,7 +1822,6 @@ public Reporting getReporting()
public void setReportArtifacts( Set reportArtifacts )
{
this.reportArtifacts = reportArtifacts;
-
reportArtifactMap = null;
}
@@ -1851,7 +1845,6 @@ public Map getReportArtifactMap()
public void setExtensionArtifacts( Set extensionArtifacts )
{
this.extensionArtifacts = extensionArtifacts;
-
extensionArtifactMap = null;
}
@@ -1885,7 +1878,6 @@ public List getReportPlugins()
public Xpp3Dom getReportConfiguration( String pluginGroupId, String pluginArtifactId, String reportSetId )
{
Xpp3Dom dom = null;
-
// ----------------------------------------------------------------------
// I would like to be able to lookup the Mojo object using a key but
// we have a limitation in modello that will be remedied shortly. So
@@ -1995,5 +1987,14 @@ private static class ArtifactsHolder
private ArtifactFilter artifactFilter;
private Set artifacts;
private Map artifactMap;
+
+ ArtifactsHolder copy()
+ {
+ ArtifactsHolder copy = new ArtifactsHolder();
+ copy.artifactFilter = artifactFilter;
+ copy.artifacts = artifacts != null ? new LinkedHashSet<>( artifacts ) : null;
+ copy.artifactMap = artifactMap != null ? new LinkedHashMap<>( artifactMap ) : null;
+ return copy;
+ }
}
}
diff --git a/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java b/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java
index 6b4258b3fde9..2344d8f77345 100644
--- a/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java
@@ -21,13 +21,18 @@
import java.io.File;
import java.io.IOException;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Profile;
+import org.mockito.Mockito;
public class MavenProjectTest
extends AbstractMavenProjectTestCase
@@ -188,6 +193,44 @@ public void testCloneWithBaseDir()
assertEquals( "Base directory is preserved across clone", projectToClone.getBasedir(), clonedProject.getBasedir() );
}
+ public void testCloneWithArtifacts()
+ throws InterruptedException
+ {
+ Artifact initialArtifact = Mockito.mock( Artifact.class, "initialArtifact" );
+ MavenProject originalProject = new MavenProject();
+ originalProject.setArtifacts( Collections.singleton( initialArtifact ) );
+ assertEquals( "Sanity check: originalProject returns artifact that has just been set",
+ Collections.singleton( initialArtifact ), originalProject.getArtifacts() );
+
+ final MavenProject clonedProject = originalProject.clone();
+
+ assertEquals( "Cloned project returns the artifact that was set for the original project",
+ Collections.singleton( initialArtifact ), clonedProject.getArtifacts() );
+
+ Artifact anotherArtifact = Mockito.mock( Artifact.class, "anotherArtifact" );
+ clonedProject.setArtifacts( Collections.singleton( anotherArtifact ) );
+ assertEquals( "Sanity check: clonedProject returns artifact that has just been set",
+ Collections.singleton( anotherArtifact ), clonedProject.getArtifacts() );
+
+ assertEquals( "Original project returns the artifact that was set initially (not the one for clonedProject)",
+ Collections.singleton( initialArtifact ), originalProject.getArtifacts() );
+
+ final AtomicReference> artifactsFromThread = new AtomicReference<>();
+ Thread thread = new Thread( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ artifactsFromThread.set( clonedProject.getArtifacts() );
+ }
+ } );
+ thread.start();
+ thread.join();
+
+ assertEquals( "Another thread does not see the same artifacts",
+ Collections.emptySet(), artifactsFromThread.get() );
+ }
+
public void testUndefinedOutputDirectory()
throws Exception
{
From 1ea42b0371f1bc99a4e0629c3734ad4ccfc0dcbd Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Sat, 11 Sep 2021 13:43:19 +0200
Subject: [PATCH 082/188] [MNG-7219] [Regression] plexus-cipher missing from
transitive dependencies
---
apache-maven/pom.xml | 4 ----
maven-compat/pom.xml | 5 -----
maven-core/pom.xml | 5 -----
3 files changed, 14 deletions(-)
diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml
index a4cf0396c61b..d98d4326f002 100644
--- a/apache-maven/pom.xml
+++ b/apache-maven/pom.xml
@@ -113,10 +113,6 @@ under the License.
org.fusesource.jansijansi
-
- org.codehaus.plexus
- plexus-cipher
-
diff --git a/maven-compat/pom.xml b/maven-compat/pom.xml
index 06686b980a5d..46259815a4fe 100644
--- a/maven-compat/pom.xml
+++ b/maven-compat/pom.xml
@@ -99,11 +99,6 @@ under the License.
wagon-provider-api
-
- org.codehaus.plexus
- plexus-cipher
- test
- org.apache.maven.wagonwagon-file
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index 60b958f1f6fb..b3f048b3c07c 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -122,11 +122,6 @@ under the License.
org.codehaus.plexusplexus-component-annotations
-
- org.codehaus.plexus
- plexus-cipher
- test
- org.apache.commonscommons-lang3
From 98a9d089bda8870fd658208d98bdc73a5f039b0f Mon Sep 17 00:00:00 2001
From: Guillaume Nodet
Date: Thu, 9 Sep 2021 16:25:21 +0200
Subject: [PATCH 083/188] [MNG-7236] The DefaultPluginVersionResolver should
cache results for the session
---
.../DefaultPluginVersionResolver.java | 89 ++++++++++++++++++-
1 file changed, 85 insertions(+), 4 deletions(-)
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java
index 82e32fb310b3..2d2d1cba7b41 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java
@@ -25,7 +25,10 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.maven.artifact.repository.metadata.Metadata;
import org.apache.maven.artifact.repository.metadata.Versioning;
@@ -49,6 +52,7 @@
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.RequestTrace;
+import org.eclipse.aether.SessionData;
import org.eclipse.aether.metadata.DefaultMetadata;
import org.eclipse.aether.repository.ArtifactRepository;
import org.eclipse.aether.repository.RemoteRepository;
@@ -72,6 +76,8 @@ public class DefaultPluginVersionResolver
private static final String REPOSITORY_CONTEXT = "plugin";
+ private static final Object CACHE_KEY = new Object();
+
@Requirement
private Logger logger;
@@ -91,12 +97,26 @@ public PluginVersionResult resolve( PluginVersionRequest request )
if ( result == null )
{
- result = resolveFromRepository( request );
+ ConcurrentMap cache = getCache( request.getRepositorySession().getData() );
+ Key key = getKey( request );
+ result = cache.get( key );
- if ( logger.isDebugEnabled() )
+ if ( result == null )
{
- logger.debug( "Resolved plugin version for " + request.getGroupId() + ":" + request.getArtifactId()
- + " to " + result.getVersion() + " from repository " + result.getRepository() );
+ result = resolveFromRepository( request );
+
+ if ( logger.isDebugEnabled() )
+ {
+ logger.debug( "Resolved plugin version for " + request.getGroupId() + ":" + request.getArtifactId()
+ + " to " + result.getVersion() + " from repository " + result.getRepository() );
+ }
+
+ cache.putIfAbsent( key, result );
+ }
+ else if ( logger.isDebugEnabled() )
+ {
+ logger.debug( "Reusing cached resolved plugin version for " + request.getGroupId() + ":"
+ + request.getArtifactId() + " to " + result.getVersion() + " from POM " + request.getPom() );
}
}
else if ( logger.isDebugEnabled() )
@@ -384,6 +404,67 @@ private PluginVersionResult resolveFromProject( PluginVersionRequest request, Li
return null;
}
+ @SuppressWarnings( "unchecked" )
+ private ConcurrentMap getCache( SessionData data )
+ {
+ ConcurrentMap cache =
+ ( ConcurrentMap ) data.get( CACHE_KEY );
+ while ( cache == null )
+ {
+ cache = new ConcurrentHashMap<>( 256 );
+ if ( data.set( CACHE_KEY, null, cache ) )
+ {
+ break;
+ }
+ cache = ( ConcurrentMap ) data.get( CACHE_KEY );
+ }
+ return cache;
+ }
+
+ private static Key getKey( PluginVersionRequest request )
+ {
+ return new Key( request.getGroupId(), request.getArtifactId(), request.getRepositories() );
+ }
+
+ static class Key
+ {
+ final String groupId;
+ final String artifactId;
+ final List repositories;
+ final int hash;
+
+ Key( String groupId, String artifactId, List repositories )
+ {
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.repositories = repositories;
+ this.hash = Objects.hash( groupId, artifactId, repositories );
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o )
+ {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() )
+ {
+ return false;
+ }
+ Key key = ( Key ) o;
+ return groupId.equals( key.groupId )
+ && artifactId.equals( key.artifactId )
+ && repositories.equals( key.repositories );
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return hash;
+ }
+ }
+
static class Versions
{
From 93f9e85955abb40bb090bad689f15fa9969ef9ba Mon Sep 17 00:00:00 2001
From: Romain Manni-Bucau
Date: Thu, 3 Dec 2020 20:07:03 +0100
Subject: [PATCH 084/188] [MNG-7045] Drop CDI API from Maven
This closes #540
---
maven-core/src/main/resources/META-INF/maven/extension.xml | 4 +++-
pom.xml | 6 ++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/maven-core/src/main/resources/META-INF/maven/extension.xml b/maven-core/src/main/resources/META-INF/maven/extension.xml
index 1fa9d41750b6..73bee382de9c 100644
--- a/maven-core/src/main/resources/META-INF/maven/extension.xml
+++ b/maven-core/src/main/resources/META-INF/maven/extension.xml
@@ -94,9 +94,11 @@ under the License.
javax.inject.*
-
+
javax.annotation.*
diff --git a/pom.xml b/pom.xml
index 9e68774899cc..65f5d22411a2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -249,6 +249,12 @@ under the License.
org.eclipse.sisuorg.eclipse.sisu.plexus${sisuVersion}
+
+
+ javax.enterprise
+ cdi-api
+
+ org.eclipse.sisu
From d1aa1e1f0a891609256c60b2b7b5b8efaceea563 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Thu, 16 Sep 2021 10:08:23 +0200
Subject: [PATCH 085/188] [MNG-7252] Fix warnings issued by dependency:analyze
This closes #541
---
maven-core/pom.xml | 8 ++++++++
maven-embedder/pom.xml | 1 +
.../apache/maven/model/building/FileModelSourceTest.java | 4 ++--
maven-resolver-provider/pom.xml | 4 ----
4 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index b3f048b3c07c..748ce6cd3960 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -118,6 +118,10 @@ under the License.
org.codehaus.plexusplexus-classworlds
+
+ org.codehaus.plexus
+ plexus-interpolation
+ org.codehaus.plexusplexus-component-annotations
@@ -126,6 +130,10 @@ under the License.
org.apache.commonscommons-lang3
+
+ org.slf4j
+ slf4j-api
+ commons-jxpathcommons-jxpath
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index 232bb9031048..7a3cc7e0d14a 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -114,6 +114,7 @@ under the License.
javax.injectjavax.inject
+
javax.annotationjavax.annotation-api
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java
index 9b0ecd9ddf57..6c8ebe0e4220 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java
@@ -22,7 +22,7 @@
import java.io.IOException;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
-import org.apache.commons.lang3.SystemUtils;
+import org.codehaus.plexus.util.Os;;
import static org.junit.Assume.assumeTrue;
import org.junit.Test;
@@ -53,7 +53,7 @@ public void testEquals()
public void testWindowsPaths()
throws Exception
{
- assumeTrue( SystemUtils.IS_OS_WINDOWS );
+ assumeTrue( Os.isFamily( "Windows" ) );
File upperCaseFile = createTempFile( "TESTE" );
String absolutePath = upperCaseFile.getAbsolutePath();
diff --git a/maven-resolver-provider/pom.xml b/maven-resolver-provider/pom.xml
index 70e0f4e5bc35..ca317a9edeca 100644
--- a/maven-resolver-provider/pom.xml
+++ b/maven-resolver-provider/pom.xml
@@ -108,10 +108,6 @@ under the License.
mockito-coretest
-
- org.slf4j
- slf4j-api
- org.slf4jslf4j-simple
From 8c66edc0417f37540b3a6ef4b266ff88bdbd8327 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Thu, 16 Sep 2021 13:52:15 +0200
Subject: [PATCH 086/188] [MNG-7254] Expand Windows native libraries for Jansi
due to JDK-8195129 (workaround)
This closes #542
---
apache-maven/pom.xml | 16 ++++++++++++++++
apache-maven/src/bin/mvn | 1 +
apache-maven/src/bin/mvn.cmd | 1 +
apache-maven/src/lib/jansi-native/README.txt | 8 ++++++++
.../src/main/assembly/.component.xml.swp | Bin 0 -> 12288 bytes
apache-maven/src/main/assembly/component.xml | 7 +++++++
6 files changed, 33 insertions(+)
create mode 100644 apache-maven/src/lib/jansi-native/README.txt
create mode 100644 apache-maven/src/main/assembly/.component.xml.swp
diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml
index d98d4326f002..b6068d0fc972 100644
--- a/apache-maven/pom.xml
+++ b/apache-maven/pom.xml
@@ -131,6 +131,22 @@ under the License.
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+ jansi
+ org/fusesource/jansi/internal/native/Windows/**
+
+
+
+ unpack-jansi-native
+
+ unpack-dependencies
+
+
+
+ org.apache.maven.pluginsmaven-compiler-plugin
diff --git a/apache-maven/src/bin/mvn b/apache-maven/src/bin/mvn
index 29e0eabb837c..90f9a758d9cf 100755
--- a/apache-maven/src/bin/mvn
+++ b/apache-maven/src/bin/mvn
@@ -197,5 +197,6 @@ exec "$JAVACMD" \
-classpath "${CLASSWORLDS_JAR}" \
"-Dclassworlds.conf=${MAVEN_HOME}/bin/m2.conf" \
"-Dmaven.home=${MAVEN_HOME}" \
+ "-Dlibrary.jansi.path=${MAVEN_HOME}/lib/jansi-native" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${CLASSWORLDS_LAUNCHER} "$@"
diff --git a/apache-maven/src/bin/mvn.cmd b/apache-maven/src/bin/mvn.cmd
index fcb0f455a804..9fb4a98c7e24 100644
--- a/apache-maven/src/bin/mvn.cmd
+++ b/apache-maven/src/bin/mvn.cmd
@@ -174,6 +174,7 @@ set CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
-classpath %CLASSWORLDS_JAR% ^
"-Dclassworlds.conf=%MAVEN_HOME%\bin\m2.conf" ^
"-Dmaven.home=%MAVEN_HOME%" ^
+ "-Dlibrary.jansi.path=%MAVEN_HOME%\lib\jansi-native" ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%CLASSWORLDS_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
if ERRORLEVEL 1 goto error
diff --git a/apache-maven/src/lib/jansi-native/README.txt b/apache-maven/src/lib/jansi-native/README.txt
new file mode 100644
index 000000000000..26a957e1b564
--- /dev/null
+++ b/apache-maven/src/lib/jansi-native/README.txt
@@ -0,0 +1,8 @@
+This directory contains Jansi native libraries extracted from Jansi JAR.
+
+You can add your own build for platforms not natively supported by Jansi.
+See here [1] on how to compile for your platform and and here [2] how libraries
+follow Jansi's directory and filename conventions.
+
+[1] https://github.com/fusesource/jansi/tree/master/src/main/native
+[2] https://github.com/fusesource/jansi/blob/321a8ff71c731e10f4ea05c607860180276b2215/src/main/java/org/fusesource/jansi/internal/OSInfo.java
diff --git a/apache-maven/src/main/assembly/.component.xml.swp b/apache-maven/src/main/assembly/.component.xml.swp
new file mode 100644
index 0000000000000000000000000000000000000000..52c487e4a78f44dad9a6220103ec18dab7e0e89c
GIT binary patch
literal 12288
zcmeI2Ux*t;9LJ|sYpb?O1w{mz#)@sd?B=c%+iN^X?{XNt>p#tp?;n+atIrV|a#CCfJl4>gbba*>_Y%xqgrOqiBu*)5js7nErf
z)0S;d3MRDCZM%tQre9M9QUyj(AkdBM;hhTyC&qK3^@Eu`^zPjYBQ#7+QUy{4QUy{4
zQUy{4QUy{4QUy{4ZWINyw}m{1V7A5qHRI1MD?a05`jIM-Dv&CWDv&CWDv&CWDv&CW
zDv&CWDv&CWD)2v4z;X!r34XsB{sI7h{~!GS|H_?&dC3Q@E!beJ0V|#3*cFB7VHQ2g00}k+X%S`UIEX5BVZT!V+SGM
zf-k_Q;C*l&ya0S)g9Weye7T*F&%s;ZMG$}nI1L^Kzu!v8_uw;d5nKT0z#_S
zWg8(sfUm&YKm!{T!9lPW+yj2Tg^*9cyWmyefv3PxFa{m~zugR7`z9zO{FPsEEuR3HB9!LM26tJNX%&_d<$e(r
zGSFV2XSmO7E&bk<%jyQWQ|%?uTlDe+lYy?V
z*ptoDT8k@+e@ar_vNWA8QPoqLwH383K|SVk>2TX}-5&J=0V75|UxrTmG@DI4Ez#c$
zs|U@sdQ8}?x;=1s7{jW}*SQ!q6OrjA6Oqu>k!sUAA29mqAH*2vCXoqPw4MK6+=G!Z
z6h7(lfot#=ubsJQ3B|L*(tL@Hk~D4kO{PtUc}zG=*gZ3EZZdz@J&wARdK138+{RHk
zrp$i3f7|;J=gC<3q4U==XRfDwWxiILF0L9yi7_^Z`<3cylZ__?1A}Dal^~8VI*^!E
zEz4(4*7EHZMrPJ$N(R1-q?L=cLbgqn|_DL1W}2X=-CZYFU9YJePF?HQE2j+Ahv&oBgGFd%@2lqTbw^~NSaguo)&*blhGpxihUF?u9&6l*y3DVk!V19#(G7>+T60_|
z%_#A%nAkTSp6kyaYlOAwfUlMy3a+d8q{0E*wlybhOute*mT772O`84lxkmqdu7Rk{
zLbX~fADcUqot`frpRW`vHFLtq89Dk-4Z6x1p5)CAPx5A?Mh0$XrbvERO>w|isLl7D
z={KB2B*Vs?PRHmRjGUgpxn%Qnd9E4-ndL%hOV}(!!re%K#lw#_DRceV*dWSdHg9m7
zx|V1LR+G`DTw=b!hAQ0Nw7F6cNl{BU)a7liBheIjqEwj~ql{z6<5Sl4FjXijeahRO
z%b8Z=ytVyO&rKM_y9xGH!)iHXiRC|1Wp+-*?PMj!IYNcY8&Yz&u^Oc!W
ztu$XjX_gi$XNZyw-NEcc9j>&`>w#ttT@_HcSxXv70nf>Ta6|We_H=+9utV!TYI*R}
zw(2fJo3I7Ux0KTITrk91#{2A?%8KioG*-uS%P(o}W?%v#)o(=}{m3)NX9y}xcR
zdq9!`$Kk>`OnhgfBwLOH@uaX^IEk#cqai~eaa$sP*a!CWhl=>&eeH3SUaQ2w>937Z
k&?Jr{N)NoJad_3ipqP~iJ?e+**
+
+ target/dependency/org/fusesource/jansi/internal/native
+ lib/jansi-native
+
+ **
+
+ src/binbin
From ab54d17dc2ec355c1e002e8751739edd9a96fcc3 Mon Sep 17 00:00:00 2001
From: George Gastaldi
Date: Fri, 17 Sep 2021 12:18:27 -0300
Subject: [PATCH 087/188] [MNG-7253] Display relocation message defined in
model
Move logging to DefaultArtifactDescriptorReader
This closes #544
---
.../DefaultProjectDependenciesResolver.java | 12 ------------
.../DefaultArtifactDescriptorReader.java | 18 ++++++++++++++++--
2 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectDependenciesResolver.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectDependenciesResolver.java
index 7500e43d2a38..3644b67ef408 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectDependenciesResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectDependenciesResolver.java
@@ -181,18 +181,6 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request )
depRequest.setRoot( node );
- if ( logger.isWarnEnabled() )
- {
- for ( DependencyNode child : node.getChildren() )
- {
- if ( !child.getRelocations().isEmpty() )
- {
- logger.warn( "The artifact " + child.getRelocations().get( 0 ) + " has been relocated to "
- + child.getDependency().getArtifact() );
- }
- }
- }
-
if ( logger.isDebugEnabled() )
{
node.accept( new GraphLogger( project ) );
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java
index c2ba0a3d729a..888f4581b460 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java
@@ -68,6 +68,8 @@
import org.eclipse.aether.spi.locator.Service;
import org.eclipse.aether.spi.locator.ServiceLocator;
import org.eclipse.aether.transfer.ArtifactNotFoundException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* @author Benjamin Bentmann
@@ -77,6 +79,8 @@
public class DefaultArtifactDescriptorReader
implements ArtifactDescriptorReader, Service
{
+ private static final Logger LOGGER = LoggerFactory.getLogger( DefaultArtifactDescriptorReader.class );
+
private RemoteRepositoryManager remoteRepositoryManager;
private VersionResolver versionResolver;
@@ -316,10 +320,20 @@ private Model loadPom( RepositorySystemSession session, ArtifactDescriptorReques
if ( relocation != null )
{
result.addRelocation( a );
- a =
+ Artifact relocatedArtifact =
new RelocatedArtifact( a, relocation.getGroupId(), relocation.getArtifactId(),
relocation.getVersion() );
- result.setArtifact( a );
+ if ( LOGGER.isWarnEnabled() )
+ {
+ String message = "The artifact " + a + " has been relocated to " + relocatedArtifact;
+ if ( relocation.getMessage() != null )
+ {
+ message += ": " + relocation.getMessage();
+ }
+ LOGGER.warn( message );
+ }
+ result.setArtifact( relocatedArtifact );
+ a = relocatedArtifact;
}
else
{
From 8882a9c599013182e42f0c7c321396c23b84dbe0 Mon Sep 17 00:00:00 2001
From: Gary Gregory
Date: Sat, 29 May 2021 09:31:49 -0400
Subject: [PATCH 088/188] [MNG-7164] Add constructor
MojoExecutionException(Throwable)
This closes #474
---
.../plugin/AbstractMojoExecutionException.java | 12 ++++++++++++
.../apache/maven/plugin/MojoExecutionException.java | 13 +++++++++++++
.../apache/maven/plugin/MojoFailureException.java | 13 +++++++++++++
3 files changed, 38 insertions(+)
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java
index 52aded3d654d..e8df3095f212 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java
@@ -41,6 +41,18 @@ public AbstractMojoExecutionException( String message, Throwable cause )
super( message, cause );
}
+ /**
+ * Constructs a new {@code AbstractMojoExecutionException} exception wrapping an underlying {@code Throwable}.
+ *
+ * @param cause the cause which is saved for later retrieval by the {@link #getCause()} method.
+ * A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.
+ * @since 3.8.3
+ */
+ public AbstractMojoExecutionException( Throwable cause )
+ {
+ super( cause );
+ }
+
public String getLongMessage()
{
return longMessage;
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java
index 4d8c416e077d..6d089898600c 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java
@@ -76,4 +76,17 @@ public MojoExecutionException( String message )
{
super( message );
}
+
+ /**
+ * Constructs a new {@code MojoExecutionException} exception wrapping an underlying {@code Throwable}.
+ *
+ * @param cause the cause which is saved for later retrieval by the {@link #getCause()} method.
+ * A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.
+ * @since 3.8.3
+ */
+ public MojoExecutionException( Throwable cause )
+ {
+ super( cause );
+ }
+
}
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java
index 342d081f00b2..72faec679eb9 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java
@@ -65,4 +65,17 @@ public MojoFailureException( String message, Throwable cause )
{
super( message, cause );
}
+
+ /**
+ * Constructs a new {@code MojoFailureException} exception wrapping an underlying {@code Throwable}.
+ *
+ * @param cause the cause which is saved for later retrieval by the {@link #getCause()} method.
+ * A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.
+ * @since 3.8.3
+ */
+ public MojoFailureException( Throwable cause )
+ {
+ super( cause );
+ }
+
}
From 0a6bbb8301717d386e6588a7ea32e3e2451c7060 Mon Sep 17 00:00:00 2001
From: Guillaume Nodet
Date: Thu, 9 Sep 2021 16:10:25 +0200
Subject: [PATCH 089/188] [MNG-7235] Speed improvements when calculating the
sorted project graph
This closes #530
---
.../graph/DefaultProjectDependencyGraph.java | 49 ++++++++++++++++---
1 file changed, 41 insertions(+), 8 deletions(-)
diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java
index e0067f1fe4ae..7804312c9f90 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java
@@ -22,8 +22,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -42,9 +45,13 @@ public class DefaultProjectDependencyGraph
implements ProjectDependencyGraph
{
- private ProjectSorter sorter;
+ private final ProjectSorter sorter;
- private List allProjects;
+ private final List allProjects;
+
+ private final Map order;
+
+ private final Map projects;
/**
* Creates a new project dependency graph based on the specified projects.
@@ -59,6 +66,16 @@ public DefaultProjectDependencyGraph( Collection projects )
super();
this.allProjects = Collections.unmodifiableList( new ArrayList<>( projects ) );
this.sorter = new ProjectSorter( projects );
+ List sorted = this.sorter.getSortedProjects();
+ this.order = new HashMap<>( sorted.size() );
+ this.projects = new HashMap<>( sorted.size() );
+ int index = 0;
+ for ( MavenProject project : sorted )
+ {
+ String id = ProjectSorter.getId( project );
+ this.projects.put( id, project );
+ this.order.put( project, index++ );
+ }
}
/**
@@ -78,6 +95,16 @@ public DefaultProjectDependencyGraph( final List allProjects,
super();
this.allProjects = Collections.unmodifiableList( new ArrayList<>( allProjects ) );
this.sorter = new ProjectSorter( projects );
+ List sorted = this.sorter.getSortedProjects();
+ this.order = new HashMap<>( sorted.size() );
+ this.projects = new HashMap<>( sorted.size() );
+ int index = 0;
+ for ( MavenProject project : sorted )
+ {
+ String id = ProjectSorter.getId( project );
+ this.projects.put( id, project );
+ this.order.put( project, index++ );
+ }
}
/**
@@ -140,15 +167,13 @@ private void getUpstreamProjects( String projectId, Collection projectId
private List getSortedProjects( Set projectIds )
{
List result = new ArrayList<>( projectIds.size() );
-
- for ( MavenProject mavenProject : sorter.getSortedProjects() )
+ for ( String projectId : projectIds )
{
- if ( projectIds.contains( ProjectSorter.getId( mavenProject ) ) )
- {
- result.add( mavenProject );
- }
+ result.add( projects.get( projectId ) );
}
+ Collections.sort( result, new MavenProjectComparator() );
+
return result;
}
@@ -158,4 +183,12 @@ public String toString()
return sorter.getSortedProjects().toString();
}
+ private class MavenProjectComparator implements Comparator
+ {
+ @Override
+ public int compare( MavenProject o1, MavenProject o2 )
+ {
+ return order.get( o1 ) - order.get( o2 );
+ }
+ }
}
From ff8e977a158738155dc465c6a97ffaf31982d739 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Mon, 27 Sep 2021 20:28:25 +0200
Subject: [PATCH 090/188] [maven-release-plugin] prepare release maven-3.8.3
---
apache-maven/pom.xml | 2 +-
maven-artifact/pom.xml | 2 +-
maven-builder-support/pom.xml | 2 +-
maven-compat/pom.xml | 2 +-
maven-core/pom.xml | 2 +-
maven-embedder/pom.xml | 2 +-
maven-model-builder/pom.xml | 2 +-
maven-model/pom.xml | 2 +-
maven-plugin-api/pom.xml | 2 +-
maven-repository-metadata/pom.xml | 2 +-
maven-resolver-provider/pom.xml | 2 +-
maven-settings-builder/pom.xml | 2 +-
maven-settings/pom.xml | 2 +-
maven-slf4j-provider/pom.xml | 2 +-
pom.xml | 6 +++---
15 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml
index b6068d0fc972..c17f8a6d5e6a 100644
--- a/apache-maven/pom.xml
+++ b/apache-maven/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3apache-maven
diff --git a/maven-artifact/pom.xml b/maven-artifact/pom.xml
index 5203f1b79592..6cf8468499a4 100644
--- a/maven-artifact/pom.xml
+++ b/maven-artifact/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-artifact
diff --git a/maven-builder-support/pom.xml b/maven-builder-support/pom.xml
index 191bfc5967d0..959d8ec3fc84 100644
--- a/maven-builder-support/pom.xml
+++ b/maven-builder-support/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-builder-support
diff --git a/maven-compat/pom.xml b/maven-compat/pom.xml
index 46259815a4fe..75e2289d2f06 100644
--- a/maven-compat/pom.xml
+++ b/maven-compat/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-compat
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index 748ce6cd3960..d4c5111666c3 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-core
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index 7a3cc7e0d14a..1c632c93f884 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-embedder
diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml
index 06d42d38e31b..8cb1008a6675 100644
--- a/maven-model-builder/pom.xml
+++ b/maven-model-builder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-model-builder
diff --git a/maven-model/pom.xml b/maven-model/pom.xml
index 0e002c0c2f5e..df81d72f91c0 100644
--- a/maven-model/pom.xml
+++ b/maven-model/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-model
diff --git a/maven-plugin-api/pom.xml b/maven-plugin-api/pom.xml
index a0a708926b69..a1a72a1967b4 100644
--- a/maven-plugin-api/pom.xml
+++ b/maven-plugin-api/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-plugin-api
diff --git a/maven-repository-metadata/pom.xml b/maven-repository-metadata/pom.xml
index b4ac0f489b00..4b4cc2b88999 100644
--- a/maven-repository-metadata/pom.xml
+++ b/maven-repository-metadata/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-repository-metadata
diff --git a/maven-resolver-provider/pom.xml b/maven-resolver-provider/pom.xml
index ca317a9edeca..52e94e5c3c7b 100644
--- a/maven-resolver-provider/pom.xml
+++ b/maven-resolver-provider/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-resolver-provider
diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml
index dd0c09bb9ce8..677c13999c0c 100644
--- a/maven-settings-builder/pom.xml
+++ b/maven-settings-builder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-settings-builder
diff --git a/maven-settings/pom.xml b/maven-settings/pom.xml
index 6fa967c38ca3..b77437c27c9a 100644
--- a/maven-settings/pom.xml
+++ b/maven-settings/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-settings
diff --git a/maven-slf4j-provider/pom.xml b/maven-slf4j-provider/pom.xml
index 802d226c9c0a..eea89b72de1e 100644
--- a/maven-slf4j-provider/pom.xml
+++ b/maven-slf4j-provider/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3-SNAPSHOT
+ 3.8.3maven-slf4j-provider
diff --git a/pom.xml b/pom.xml
index 65f5d22411a2..f584a2e60d55 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,7 @@ under the License.
maven
- 3.8.3-SNAPSHOT
+ 3.8.3pomApache Maven
@@ -77,7 +77,7 @@ under the License.
ref/3-LATESTNone**/package-info.java
- 2021-08-04T19:03:41Z
+ 2021-09-27T18:25:22Z
@@ -101,7 +101,7 @@ under the License.
scm:git:https://gitbox.apache.org/repos/asf/maven.gitscm:git:https://gitbox.apache.org/repos/asf/maven.githttps://github.com/apache/maven/tree/${project.scm.tag}
- maven-3.8.2
+ maven-3.8.3jira
From 21e597ec777f0b74eed4e067b58b6eb8b0c9fad4 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Mon, 27 Sep 2021 20:28:37 +0200
Subject: [PATCH 091/188] [maven-release-plugin] prepare for next development
iteration
---
apache-maven/pom.xml | 2 +-
maven-artifact/pom.xml | 2 +-
maven-builder-support/pom.xml | 2 +-
maven-compat/pom.xml | 2 +-
maven-core/pom.xml | 2 +-
maven-embedder/pom.xml | 2 +-
maven-model-builder/pom.xml | 2 +-
maven-model/pom.xml | 2 +-
maven-plugin-api/pom.xml | 2 +-
maven-repository-metadata/pom.xml | 2 +-
maven-resolver-provider/pom.xml | 2 +-
maven-settings-builder/pom.xml | 2 +-
maven-settings/pom.xml | 2 +-
maven-slf4j-provider/pom.xml | 2 +-
pom.xml | 4 ++--
15 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml
index c17f8a6d5e6a..5f713bb71c29 100644
--- a/apache-maven/pom.xml
+++ b/apache-maven/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTapache-maven
diff --git a/maven-artifact/pom.xml b/maven-artifact/pom.xml
index 6cf8468499a4..68af732ea550 100644
--- a/maven-artifact/pom.xml
+++ b/maven-artifact/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-artifact
diff --git a/maven-builder-support/pom.xml b/maven-builder-support/pom.xml
index 959d8ec3fc84..897fe185f4bc 100644
--- a/maven-builder-support/pom.xml
+++ b/maven-builder-support/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-builder-support
diff --git a/maven-compat/pom.xml b/maven-compat/pom.xml
index 75e2289d2f06..221bf2c19ccd 100644
--- a/maven-compat/pom.xml
+++ b/maven-compat/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-compat
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index d4c5111666c3..86aea1ff2319 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-core
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index 1c632c93f884..af2cd81ce593 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-embedder
diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml
index 8cb1008a6675..e08f1af28731 100644
--- a/maven-model-builder/pom.xml
+++ b/maven-model-builder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-model-builder
diff --git a/maven-model/pom.xml b/maven-model/pom.xml
index df81d72f91c0..f7e07c866bac 100644
--- a/maven-model/pom.xml
+++ b/maven-model/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-model
diff --git a/maven-plugin-api/pom.xml b/maven-plugin-api/pom.xml
index a1a72a1967b4..630a46cf283b 100644
--- a/maven-plugin-api/pom.xml
+++ b/maven-plugin-api/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-plugin-api
diff --git a/maven-repository-metadata/pom.xml b/maven-repository-metadata/pom.xml
index 4b4cc2b88999..0c9e5318dc62 100644
--- a/maven-repository-metadata/pom.xml
+++ b/maven-repository-metadata/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-repository-metadata
diff --git a/maven-resolver-provider/pom.xml b/maven-resolver-provider/pom.xml
index 52e94e5c3c7b..f941dd0e3577 100644
--- a/maven-resolver-provider/pom.xml
+++ b/maven-resolver-provider/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-resolver-provider
diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml
index 677c13999c0c..2ffbd9457d8e 100644
--- a/maven-settings-builder/pom.xml
+++ b/maven-settings-builder/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-settings-builder
diff --git a/maven-settings/pom.xml b/maven-settings/pom.xml
index b77437c27c9a..c585d573387f 100644
--- a/maven-settings/pom.xml
+++ b/maven-settings/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-settings
diff --git a/maven-slf4j-provider/pom.xml b/maven-slf4j-provider/pom.xml
index eea89b72de1e..e63956fcf359 100644
--- a/maven-slf4j-provider/pom.xml
+++ b/maven-slf4j-provider/pom.xml
@@ -25,7 +25,7 @@ under the License.
org.apache.mavenmaven
- 3.8.3
+ 3.8.4-SNAPSHOTmaven-slf4j-provider
diff --git a/pom.xml b/pom.xml
index f584a2e60d55..a5848644d563 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,7 @@ under the License.
maven
- 3.8.3
+ 3.8.4-SNAPSHOTpomApache Maven
@@ -77,7 +77,7 @@ under the License.
ref/3-LATESTNone**/package-info.java
- 2021-09-27T18:25:22Z
+ 2021-09-27T18:28:35Z
From b6186e2c7714158b5a2709f4af9d40b194c53f55 Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Mon, 27 Sep 2021 22:16:35 +0200
Subject: [PATCH 092/188] Remove swap file
---
.../src/main/assembly/.component.xml.swp | Bin 12288 -> 0 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 apache-maven/src/main/assembly/.component.xml.swp
diff --git a/apache-maven/src/main/assembly/.component.xml.swp b/apache-maven/src/main/assembly/.component.xml.swp
deleted file mode 100644
index 52c487e4a78f44dad9a6220103ec18dab7e0e89c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 12288
zcmeI2Ux*t;9LJ|sYpb?O1w{mz#)@sd?B=c%+iN^X?{XNt>p#tp?;n+atIrV|a#CCfJl4>gbba*>_Y%xqgrOqiBu*)5js7nErf
z)0S;d3MRDCZM%tQre9M9QUyj(AkdBM;hhTyC&qK3^@Eu`^zPjYBQ#7+QUy{4QUy{4
zQUy{4QUy{4QUy{4ZWINyw}m{1V7A5qHRI1MD?a05`jIM-Dv&CWDv&CWDv&CWDv&CW
zDv&CWDv&CWD)2v4z;X!r34XsB{sI7h{~!GS|H_?&dC3Q@E!beJ0V|#3*cFB7VHQ2g00}k+X%S`UIEX5BVZT!V+SGM
zf-k_Q;C*l&ya0S)g9Weye7T*F&%s;ZMG$}nI1L^Kzu!v8_uw;d5nKT0z#_S
zWg8(sfUm&YKm!{T!9lPW+yj2Tg^*9cyWmyefv3PxFa{m~zugR7`z9zO{FPsEEuR3HB9!LM26tJNX%&_d<$e(r
zGSFV2XSmO7E&bk<%jyQWQ|%?uTlDe+lYy?V
z*ptoDT8k@+e@ar_vNWA8QPoqLwH383K|SVk>2TX}-5&J=0V75|UxrTmG@DI4Ez#c$
zs|U@sdQ8}?x;=1s7{jW}*SQ!q6OrjA6Oqu>k!sUAA29mqAH*2vCXoqPw4MK6+=G!Z
z6h7(lfot#=ubsJQ3B|L*(tL@Hk~D4kO{PtUc}zG=*gZ3EZZdz@J&wARdK138+{RHk
zrp$i3f7|;J=gC<3q4U==XRfDwWxiILF0L9yi7_^Z`<3cylZ__?1A}Dal^~8VI*^!E
zEz4(4*7EHZMrPJ$N(R1-q?L=cLbgqn|_DL1W}2X=-CZYFU9YJePF?HQE2j+Ahv&oBgGFd%@2lqTbw^~NSaguo)&*blhGpxihUF?u9&6l*y3DVk!V19#(G7>+T60_|
z%_#A%nAkTSp6kyaYlOAwfUlMy3a+d8q{0E*wlybhOute*mT772O`84lxkmqdu7Rk{
zLbX~fADcUqot`frpRW`vHFLtq89Dk-4Z6x1p5)CAPx5A?Mh0$XrbvERO>w|isLl7D
z={KB2B*Vs?PRHmRjGUgpxn%Qnd9E4-ndL%hOV}(!!re%K#lw#_DRceV*dWSdHg9m7
zx|V1LR+G`DTw=b!hAQ0Nw7F6cNl{BU)a7liBheIjqEwj~ql{z6<5Sl4FjXijeahRO
z%b8Z=ytVyO&rKM_y9xGH!)iHXiRC|1Wp+-*?PMj!IYNcY8&Yz&u^Oc!W
ztu$XjX_gi$XNZyw-NEcc9j>&`>w#ttT@_HcSxXv70nf>Ta6|We_H=+9utV!TYI*R}
zw(2fJo3I7Ux0KTITrk91#{2A?%8KioG*-uS%P(o}W?%v#)o(=}{m3)NX9y}xcR
zdq9!`$Kk>`OnhgfBwLOH@uaX^IEk#cqai~eaa$sP*a!CWhl=>&eeH3SUaQ2w>937Z
k&?Jr{N)NoJad_3ipqP~iJ?e+
Date: Wed, 29 Sep 2021 11:29:35 +0100
Subject: [PATCH 093/188] [MNG-7270] Switch to shell alternative to "which"
In some circumstances the init script calls `which`, which may or may not be
available on the host system. Instead, use `command -v`, which is nearly
equivalent. One area it differs is if the command being queried is defined as
a shell alias. To avoid that, call `unset -f command` to avoid the situation
where "command" has been re-defined as a shell function.
See here for more information on this approach:
Tested with bash, sh (bash invoked as sh), posh, dash, zsh and mksh.
This closes #556
---
apache-maven/src/bin/mvn | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apache-maven/src/bin/mvn b/apache-maven/src/bin/mvn
index 90f9a758d9cf..dfa384b8e141 100755
--- a/apache-maven/src/bin/mvn
+++ b/apache-maven/src/bin/mvn
@@ -94,7 +94,7 @@ if $mingw ; then
fi
if [ -z "$JAVA_HOME" ] ; then
- JAVACMD=`which java`
+ JAVACMD="`\\unset -f command; \\command -v java`"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
From 5c36bf5ef78a162cefea47ccdaf0d28e01c1426c Mon Sep 17 00:00:00 2001
From: Michael Osipov
Date: Sat, 16 Oct 2021 15:21:28 +0200
Subject: [PATCH 094/188] [MNG-7312] Revert ThreadLocal approach from MNG-6843
and MNG-7251
Revert "[MNG-7251] Fix threadLocalArtifactsHolder leaking into cloned project"
This reverts commit 4e5b3d55545e5f03f05ac7b0cd1b56689df36201.
Revert "[MNG-6843] Parallel build fails due to missing JAR artifacts in compilePath"
This reverts commit 76d5f0d942f52650d3bdf775b6af42d23d69066b.
===
This closes #595
---
.../apache/maven/project/MavenProject.java | 102 +++++++++---------
.../maven/project/MavenProjectTest.java | 43 --------
2 files changed, 48 insertions(+), 97 deletions(-)
diff --git a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
index 94d678814534..db0f4a90116f 100644
--- a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
+++ b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
@@ -92,9 +92,13 @@
public class MavenProject
implements Cloneable
{
+
private static final Logger LOGGER = LoggerFactory.getLogger( MavenProject.class );
+
public static final String EMPTY_PROJECT_GROUP_ID = "unknown";
+
public static final String EMPTY_PROJECT_ARTIFACT_ID = "empty-project";
+
public static final String EMPTY_PROJECT_VERSION = "0";
private Model model;
@@ -107,6 +111,10 @@ public class MavenProject
private Set resolvedArtifacts;
+ private ArtifactFilter artifactFilter;
+
+ private Set artifacts;
+
private Artifact parentArtifact;
private Set pluginArtifacts;
@@ -143,7 +151,8 @@ public class MavenProject
private Artifact artifact;
- private ThreadLocal threadLocalArtifactsHolder = newThreadLocalArtifactsHolder();
+ // calculated.
+ private Map artifactMap;
private Model originalModel;
@@ -176,21 +185,12 @@ public class MavenProject
public MavenProject()
{
Model model = new Model();
+
model.setGroupId( EMPTY_PROJECT_GROUP_ID );
model.setArtifactId( EMPTY_PROJECT_ARTIFACT_ID );
model.setVersion( EMPTY_PROJECT_VERSION );
- setModel( model );
- }
- private static ThreadLocal newThreadLocalArtifactsHolder()
- {
- return new ThreadLocal()
- {
- protected ArtifactsHolder initialValue()
- {
- return new ArtifactsHolder();
- }
- };
+ setModel( model );
}
public MavenProject( Model model )
@@ -695,11 +695,10 @@ public void addLicense( License license )
public void setArtifacts( Set artifacts )
{
- ArtifactsHolder artifactsHolder = threadLocalArtifactsHolder.get();
- artifactsHolder.artifacts = artifacts;
+ this.artifacts = artifacts;
// flush the calculated artifactMap
- artifactsHolder.artifactMap = null;
+ artifactMap = null;
}
/**
@@ -712,36 +711,34 @@ public void setArtifacts( Set artifacts )
*/
public Set getArtifacts()
{
- ArtifactsHolder artifactsHolder = threadLocalArtifactsHolder.get();
- if ( artifactsHolder.artifacts == null )
+ if ( artifacts == null )
{
- if ( artifactsHolder.artifactFilter == null || resolvedArtifacts == null )
+ if ( artifactFilter == null || resolvedArtifacts == null )
{
- artifactsHolder.artifacts = new LinkedHashSet<>();
+ artifacts = new LinkedHashSet<>();
}
else
{
- artifactsHolder.artifacts = new LinkedHashSet<>( resolvedArtifacts.size() * 2 );
+ artifacts = new LinkedHashSet<>( resolvedArtifacts.size() * 2 );
for ( Artifact artifact : resolvedArtifacts )
{
- if ( artifactsHolder.artifactFilter.include( artifact ) )
+ if ( artifactFilter.include( artifact ) )
{
- artifactsHolder.artifacts.add( artifact );
+ artifacts.add( artifact );
}
}
}
}
- return artifactsHolder.artifacts;
+ return artifacts;
}
public Map getArtifactMap()
{
- ArtifactsHolder artifactsHolder = threadLocalArtifactsHolder.get();
- if ( artifactsHolder.artifactMap == null )
+ if ( artifactMap == null )
{
- artifactsHolder.artifactMap = ArtifactUtils.artifactMapByVersionlessId( getArtifacts() );
+ artifactMap = ArtifactUtils.artifactMapByVersionlessId( getArtifacts() );
}
- return artifactsHolder.artifactMap;
+ return artifactMap;
}
public void setPluginArtifacts( Set pluginArtifacts )
@@ -1186,8 +1183,7 @@ public MavenProject clone()
{
throw new UnsupportedOperationException( e );
}
- // clone must have it's own TL, otherwise the artifacts are intermingled!
- clone.threadLocalArtifactsHolder = newThreadLocalArtifactsHolder();
+
clone.deepCopy( this );
return clone;
@@ -1230,7 +1226,6 @@ private void deepCopy( MavenProject project )
// copy fields
file = project.file;
basedir = project.basedir;
- threadLocalArtifactsHolder.set( project.threadLocalArtifactsHolder.get().copy() );
// don't need a deep copy, they don't get modified or added/removed to/from - but make them unmodifiable to be
// sure!
@@ -1239,6 +1234,11 @@ private void deepCopy( MavenProject project )
setDependencyArtifacts( Collections.unmodifiableSet( project.getDependencyArtifacts() ) );
}
+ if ( project.getArtifacts() != null )
+ {
+ setArtifacts( Collections.unmodifiableSet( project.getArtifacts() ) );
+ }
+
if ( project.getParentFile() != null )
{
parentFile = new File( project.getParentFile().getAbsolutePath() );
@@ -1433,9 +1433,8 @@ public DependencyFilter getExtensionDependencyFilter()
public void setResolvedArtifacts( Set artifacts )
{
this.resolvedArtifacts = ( artifacts != null ) ? artifacts : Collections.emptySet();
- ArtifactsHolder artifactsHolder = threadLocalArtifactsHolder.get();
- artifactsHolder.artifacts = null;
- artifactsHolder.artifactMap = null;
+ this.artifacts = null;
+ this.artifactMap = null;
}
/**
@@ -1448,10 +1447,9 @@ public void setResolvedArtifacts( Set artifacts )
*/
public void setArtifactFilter( ArtifactFilter artifactFilter )
{
- ArtifactsHolder artifactsHolder = threadLocalArtifactsHolder.get();
- artifactsHolder.artifactFilter = artifactFilter;
- artifactsHolder.artifacts = null;
- artifactsHolder.artifactMap = null;
+ this.artifactFilter = artifactFilter;
+ this.artifacts = null;
+ this.artifactMap = null;
}
/**
@@ -1481,7 +1479,13 @@ public void addLifecyclePhase( String lifecyclePhase )
// ----------------------------------------------------------------------------------------------------------------
//
- // D E P R E C A T E D - Everything below will be removed for Maven 4.0.0
+ //
+ // D E P R E C A T E D
+ //
+ //
+ // ----------------------------------------------------------------------------------------------------------------
+ //
+ // Everything below will be removed for Maven 4.0.0
//
// ----------------------------------------------------------------------------------------------------------------
@@ -1502,6 +1506,7 @@ public String getModulePathAdjustment( MavenProject moduleProject )
if ( moduleFile != null )
{
File moduleDir = moduleFile.getCanonicalFile().getParentFile();
+
module = moduleDir.getName();
}
@@ -1822,6 +1827,7 @@ public Reporting getReporting()
public void setReportArtifacts( Set reportArtifacts )
{
this.reportArtifacts = reportArtifacts;
+
reportArtifactMap = null;
}
@@ -1838,6 +1844,7 @@ public Map getReportArtifactMap()
{
reportArtifactMap = ArtifactUtils.artifactMapByVersionlessId( getReportArtifacts() );
}
+
return reportArtifactMap;
}
@@ -1845,6 +1852,7 @@ public Map getReportArtifactMap()
public void setExtensionArtifacts( Set extensionArtifacts )
{
this.extensionArtifacts = extensionArtifacts;
+
extensionArtifactMap = null;
}
@@ -1861,6 +1869,7 @@ public Map getExtensionArtifactMap()
{
extensionArtifactMap = ArtifactUtils.artifactMapByVersionlessId( getExtensionArtifacts() );
}
+
return extensionArtifactMap;
}
@@ -1878,6 +1887,7 @@ public List getReportPlugins()
public Xpp3Dom getReportConfiguration( String pluginGroupId, String pluginArtifactId, String reportSetId )
{
Xpp3Dom dom = null;
+
// ----------------------------------------------------------------------
// I would like to be able to lookup the Mojo object using a key but
// we have a limitation in modello that will be remedied shortly. So
@@ -1981,20 +1991,4 @@ public void setProjectBuildingRequest( ProjectBuildingRequest projectBuildingReq
{
this.projectBuilderConfiguration = projectBuildingRequest;
}
-
- private static class ArtifactsHolder
- {
- private ArtifactFilter artifactFilter;
- private Set artifacts;
- private Map artifactMap;
-
- ArtifactsHolder copy()
- {
- ArtifactsHolder copy = new ArtifactsHolder();
- copy.artifactFilter = artifactFilter;
- copy.artifacts = artifacts != null ? new LinkedHashSet<>( artifacts ) : null;
- copy.artifactMap = artifactMap != null ? new LinkedHashMap<>( artifactMap ) : null;
- return copy;
- }
- }
}
diff --git a/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java b/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java
index 2344d8f77345..6b4258b3fde9 100644
--- a/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java
@@ -21,18 +21,13 @@
import java.io.File;
import java.io.IOException;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicReference;
-import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.Profile;
-import org.mockito.Mockito;
public class MavenProjectTest
extends AbstractMavenProjectTestCase
@@ -193,44 +188,6 @@ public void testCloneWithBaseDir()
assertEquals( "Base directory is preserved across clone", projectToClone.getBasedir(), clonedProject.getBasedir() );
}
- public void testCloneWithArtifacts()
- throws InterruptedException
- {
- Artifact initialArtifact = Mockito.mock( Artifact.class, "initialArtifact" );
- MavenProject originalProject = new MavenProject();
- originalProject.setArtifacts( Collections.singleton( initialArtifact ) );
- assertEquals( "Sanity check: originalProject returns artifact that has just been set",
- Collections.singleton( initialArtifact ), originalProject.getArtifacts() );
-
- final MavenProject clonedProject = originalProject.clone();
-
- assertEquals( "Cloned project returns the artifact that was set for the original project",
- Collections.singleton( initialArtifact ), clonedProject.getArtifacts() );
-
- Artifact anotherArtifact = Mockito.mock( Artifact.class, "anotherArtifact" );
- clonedProject.setArtifacts( Collections.singleton( anotherArtifact ) );
- assertEquals( "Sanity check: clonedProject returns artifact that has just been set",
- Collections.singleton( anotherArtifact ), clonedProject.getArtifacts() );
-
- assertEquals( "Original project returns the artifact that was set initially (not the one for clonedProject)",
- Collections.singleton( initialArtifact ), originalProject.getArtifacts() );
-
- final AtomicReference> artifactsFromThread = new AtomicReference<>();
- Thread thread = new Thread( new Runnable()
- {
- @Override
- public void run()
- {
- artifactsFromThread.set( clonedProject.getArtifacts() );
- }
- } );
- thread.start();
- thread.join();
-
- assertEquals( "Another thread does not see the same artifacts",
- Collections.emptySet(), artifactsFromThread.get() );
- }
-
public void testUndefinedOutputDirectory()
throws Exception
{
From c9a03660f83981a3fa71e50178c8aeae67d26219 Mon Sep 17 00:00:00 2001
From: Maximilian Novikov
Date: Tue, 10 Aug 2021 20:10:28 +0200
Subject: [PATCH 095/188] Merge pull request #4 in ABFX/maven-forked from
incremental-maven-3.6.3 to MNG-7129/maven-3.6.3-incremental
Squashed commit of the following:
commit 21c620a34ddbbf84b3c44014b069a7b222cf91a7
Author: Maximilian Novikov
Date: Tue Aug 10 19:41:41 2021 +0200
Merge pull request #3 in ABFX/maven-forked from code-cleanup-2 to incremental-maven-3.6.3
Squashed commit of the following:
commit 3401739ec9eb957fb03887f6a3c24477c9c3327b
Author: Alexander Ashitkin
Date: Tue Aug 10 13:37:13 2021 -0400
cleanup db specifics
commit 5d32f00559951445ecaf7d5ec4d847541c10e7e9
Author: Alexander Ashitkin
Date: Tue Aug 10 11:05:28 2021 -0400
cleanup db specifics
commit fcec28f82c0d447de64032c610b39fa75bb344b0
Merge: 6fd401af2 5b0dc1858
Author: Alexander Ashitkin
Date: Mon Aug 9 13:22:16 2021 +0100
Pull request #9: Remote cache setup
Merge in BND/maven-forked from feature/remote-cache-setup to incremental-maven-3.6.3
* commit '5b0dc1858cf4ca499502f0741b2f3bf2ac55530c':
remote cache setup - fail fast, baseline build, diff reporting, documentation.
commit 5b0dc1858cf4ca499502f0741b2f3bf2ac55530c
Author: Alexander Ashitkin
Date: Mon Mar 22 03:30:03 2021 +0100
remote cache setup - fail fast, baseline build, diff reporting, documentation.
commit 6fd401af285692df568312ee66ee00edfe21f1cc
Author: Maximilian Novikov
Date: Tue Apr 13 17:36:49 2021 +0100
Pull request #8: Incremental Maven - added non-overrideable cache entries
Merge in BND/maven-forked from non-overritable-build-info to incremental-maven-3.6.3
Squashed commit of the following:
commit 405bbef8a59cabc0b83e9a64717f65fbd6fb9e3d
Author: maximilian.novikov@db.com
Date: Mon Apr 12 20:18:27 2021 +0200
Incremental Maven - added non-overrideable cache entries - review fixes
commit 197704672756e558fb3521e16859d0be324044b8
Author: maximilian.novikov@db.com
Date: Fri Apr 9 11:35:48 2021 +0200
Incremental Maven - added non-overrideable cache entries
commit 64c4b1f5cbdf920ad43560f34cc5be56d4557acf
Author: Alexander Ashitkin
Date: Tue Mar 9 04:10:20 2021 +0100
injected version
commit 727e507ae2fd90dce7011f3f1c76eb4969577d5e
Author: maximilian.novikov@db.com
Date: Wed Jan 13 16:17:25 2021 +0100
Incremental Maven - Java 11 fix
commit b2f297566d5afcb0a285985cb5540685a28cafec
Author: maximilian.novikov@db.com
Date: Tue Jan 12 14:10:08 2021 +0100
Incremental Maven - initial commit
---
.gitignore | 1 +
Documentation/CACHE-HOWTO.md | 204 ++++
Documentation/CACHE-PARAMETERS.md | 52 +
Documentation/CACHE-REMOTE.md | 249 +++++
Documentation/CACHE.md | 170 ++++
Documentation/maven-cache-config.xml | 102 ++
README.md | 5 +
.../appended-resources/META-INF/LICENSE.vm | 3 +-
.../appended-resources/licenses/EDL-1.0.txt | 23 +
.../appended-resources/licenses/GPL-3.0.txt | 674 +++++++++++++
.../appended-resources/licenses/LGPL-3.0.txt | 165 +++
.../appended-resources/licenses/MPL-1.1.txt | 472 +++++++++
maven-core/pom.xml | 47 +
.../maven/caching/ArtifactsRepository.java | 42 +
.../apache/maven/caching/CacheContext.java | 58 ++
.../apache/maven/caching/CacheController.java | 52 +
.../maven/caching/CacheControllerImpl.java | 942 +++++++++++++++++
.../org/apache/maven/caching/CacheDiff.java | 345 +++++++
.../apache/maven/caching/CacheEventSpy.java | 49 +
.../org/apache/maven/caching/CacheResult.java | 122 +++
.../java/org/apache/maven/caching/Clock.java | 42 +
.../caching/DefaultPluginScanConfig.java | 63 ++
.../maven/caching/HttpRepositoryImpl.java | 336 +++++++
.../caching/LocalArtifactsRepository.java | 47 +
.../maven/caching/LocalRepositoryImpl.java | 496 +++++++++
.../maven/caching/MojoExecutionManager.java | 178 ++++
.../maven/caching/MojoParametersListener.java | 102 ++
.../maven/caching/PluginScanConfig.java | 41 +
.../maven/caching/PluginScanConfigImpl.java | 161 +++
.../apache/maven/caching/ProjectUtils.java | 197 ++++
.../caching/RemoteArtifactsRepository.java | 42 +
.../apache/maven/caching/RestoreStatus.java | 31 +
.../maven/caching/ScanConfigProperties.java | 45 +
.../org/apache/maven/caching/ZipUtils.java | 116 +++
.../DependencyNotResolvedException.java | 31 +
.../maven/caching/checksum/DigestUtils.java | 189 ++++
.../maven/caching/checksum/KeyUtils.java | 64 ++
.../caching/checksum/MavenProjectInput.java | 950 ++++++++++++++++++
.../MultimoduleDiscoveryStrategy.java | 33 +
.../maven/caching/checksum/WalkKey.java | 95 ++
.../maven/caching/hash/CloseableBuffer.java | 185 ++++
.../org/apache/maven/caching/hash/Hash.java | 61 ++
.../maven/caching/hash/HashAlgorithm.java | 46 +
.../maven/caching/hash/HashChecksum.java | 67 ++
.../maven/caching/hash/HashFactory.java | 79 ++
.../apache/maven/caching/hash/HexUtils.java | 56 ++
.../maven/caching/hash/ReflectionUtils.java | 61 ++
.../org/apache/maven/caching/hash/SHA.java | 103 ++
.../maven/caching/hash/ThreadLocalBuffer.java | 86 ++
.../maven/caching/hash/ThreadLocalDigest.java | 71 ++
.../org/apache/maven/caching/hash/XX.java | 98 ++
.../org/apache/maven/caching/hash/XXMM.java | 67 ++
.../maven/caching/xml/AllExternalSrategy.java | 42 +
.../apache/maven/caching/xml/BuildInfo.java | 273 +++++
.../apache/maven/caching/xml/CacheConfig.java | 108 ++
.../maven/caching/xml/CacheConfigImpl.java | 579 +++++++++++
.../apache/maven/caching/xml/CacheSource.java | 30 +
.../apache/maven/caching/xml/CacheState.java | 30 +
.../apache/maven/caching/xml/DtoUtils.java | 219 ++++
.../caching/xml/SentinelVersionStartegy.java | 51 +
.../apache/maven/caching/xml/XmlService.java | 145 +++
.../maven/graph/DefaultGraphBuilder.java | 73 ++
.../lifecycle/internal/DependencyContext.java | 21 +-
.../internal/IDependencyContext.java | 47 +
.../lifecycle/internal/MojoExecutor.java | 266 ++++-
.../internal/NoResolutionContext.java | 88 ++
.../plugin/DefaultBuildPluginManager.java | 40 +-
.../org/apache/maven/plugin/MojoCheker.java | 38 +
.../apache/maven/plugin/MojoExecution.java | 24 +-
.../maven/project/DefaultProjectBuilder.java | 31 +-
.../apache/maven/project/MavenProject.java | 12 +
.../main/resources/cache-config-instance.xml | 92 ++
.../src/main/resources/cache-config.xsd | 620 ++++++++++++
.../main/resources/cache-domain-instance.xml | 44 +
.../src/main/resources/cache-domain.xsd | 167 +++
.../apache/maven/caching/BuildInfoTest.java | 113 +++
.../checksum/MavenProjectInputTest.java | 85 ++
.../maven/caching/checksum/SHAHashTest.java | 72 ++
.../maven/caching/checksum/XXHashTest.java | 132 +++
.../maven/caching/hash/HexUtilsTest.java | 50 +
.../maven/caching/xml/CacheConfigTest.java | 35 +
.../internal/stub/MojoExecutorStub.java | 9 +-
pom.xml | 5 +-
83 files changed, 11472 insertions(+), 85 deletions(-)
create mode 100644 Documentation/CACHE-HOWTO.md
create mode 100644 Documentation/CACHE-PARAMETERS.md
create mode 100644 Documentation/CACHE-REMOTE.md
create mode 100644 Documentation/CACHE.md
create mode 100644 Documentation/maven-cache-config.xml
create mode 100644 apache-maven/src/main/appended-resources/licenses/EDL-1.0.txt
create mode 100644 apache-maven/src/main/appended-resources/licenses/GPL-3.0.txt
create mode 100644 apache-maven/src/main/appended-resources/licenses/LGPL-3.0.txt
create mode 100644 apache-maven/src/main/appended-resources/licenses/MPL-1.1.txt
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/ArtifactsRepository.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/CacheContext.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/CacheController.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/CacheControllerImpl.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/CacheDiff.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/CacheEventSpy.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/CacheResult.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/Clock.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/DefaultPluginScanConfig.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/HttpRepositoryImpl.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/LocalArtifactsRepository.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/LocalRepositoryImpl.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/MojoExecutionManager.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/MojoParametersListener.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/PluginScanConfig.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/PluginScanConfigImpl.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/ProjectUtils.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/RemoteArtifactsRepository.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/RestoreStatus.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/ScanConfigProperties.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/ZipUtils.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/checksum/DependencyNotResolvedException.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/checksum/DigestUtils.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/checksum/KeyUtils.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/checksum/MavenProjectInput.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/checksum/MultimoduleDiscoveryStrategy.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/checksum/WalkKey.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/CloseableBuffer.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/Hash.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/HashAlgorithm.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/HashChecksum.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/HashFactory.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/HexUtils.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/ReflectionUtils.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/SHA.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/ThreadLocalBuffer.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/ThreadLocalDigest.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/XX.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/hash/XXMM.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/xml/AllExternalSrategy.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/xml/BuildInfo.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/xml/CacheConfig.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/xml/CacheConfigImpl.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/xml/CacheSource.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/xml/CacheState.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/xml/DtoUtils.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/xml/SentinelVersionStartegy.java
create mode 100644 maven-core/src/main/java/org/apache/maven/caching/xml/XmlService.java
create mode 100644 maven-core/src/main/java/org/apache/maven/lifecycle/internal/IDependencyContext.java
create mode 100644 maven-core/src/main/java/org/apache/maven/lifecycle/internal/NoResolutionContext.java
create mode 100644 maven-core/src/main/java/org/apache/maven/plugin/MojoCheker.java
create mode 100644 maven-core/src/main/resources/cache-config-instance.xml
create mode 100644 maven-core/src/main/resources/cache-config.xsd
create mode 100644 maven-core/src/main/resources/cache-domain-instance.xml
create mode 100644 maven-core/src/main/resources/cache-domain.xsd
create mode 100644 maven-core/src/test/java/org/apache/maven/caching/BuildInfoTest.java
create mode 100644 maven-core/src/test/java/org/apache/maven/caching/checksum/MavenProjectInputTest.java
create mode 100644 maven-core/src/test/java/org/apache/maven/caching/checksum/SHAHashTest.java
create mode 100644 maven-core/src/test/java/org/apache/maven/caching/checksum/XXHashTest.java
create mode 100644 maven-core/src/test/java/org/apache/maven/caching/hash/HexUtilsTest.java
create mode 100644 maven-core/src/test/java/org/apache/maven/caching/xml/CacheConfigTest.java
diff --git a/.gitignore b/.gitignore
index f85dc5684299..5824f498a88d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ target/
.classpath
.settings/
.svn/
+.cache/
bin/
# Intellij
*.ipr
diff --git a/Documentation/CACHE-HOWTO.md b/Documentation/CACHE-HOWTO.md
new file mode 100644
index 000000000000..aa15f626af65
--- /dev/null
+++ b/Documentation/CACHE-HOWTO.md
@@ -0,0 +1,204 @@
+
+
+### Overview
+
+Cache configuration provides you additional control over incremental maven behavior. Follow it step by step to
+understand how it works and figure out your optimal config
+
+### Minimal config
+
+Absolutely minimal config which enables incremental maven with local cache
+
+```xml
+
+
+
+
+ true
+ XX
+
+
+
+
+ {*.java,*.xml,*.properties}
+
+
+
+```
+
+### Enabling remote cache
+
+Just add `` section under ``
+
+```xml
+
+
+ true
+ XX
+
+ https://yourserver:port
+
+
+```
+
+### Adding more file types to input
+
+Add all the project specific source code files in ``. Scala in this case:
+
+```xml
+
+
+
+ {*.java,*.xml,*.properties,*.scala}
+
+
+```
+
+### Adding source directory for bespoke project layouts
+
+In most of the cases incremental maven will recognize directories automatically by build introspection. If not, you can
+add additional directories with ``. Also you can filter out undesirable dirs and files by using exclude tag
+
+```xml
+
+
+
+ {*.java,*.xml,*.properties,*.scala}
+ importantdir/
+ tempfile.out
+
+
+```
+
+### Plugin property is env specific (breaks checksum and caching)
+
+Consider to exclude env specific properties:
+
+```xml
+
+
+
+ ...
+
+
+
+ argLine
+
+
+
+```
+
+Implications - builds with different `argLine` will have identical checksum. Validate that is semantically valid.
+
+### Plugin property points to directory where only subset of files is relevant
+
+If plugin configuration property points to `somedir` it will be scanned with default glob. You can tweak it with custom
+processing rule
+
+```xml
+
+
+
+ ...
+
+
+
+
+
+
+
+
+```
+
+### Local repository is not updated because `install` is cached
+
+Add `executionControl/runAlways` section
+
+```xml
+
+
+
+ ...
+
+
+ ...
+
+
+
+
+
+ unpack-autoupdate
+
+
+ install
+
+
+
+
+```
+
+### I occasionally cached build with `-DskipTests=true` and tests do not run now
+
+If you add command line flags to your build, they do not participate in effective pom - maven defers final value
+resolution to plugin runtime. To invalidate build if filed value is different in runtime, add reconciliation section
+to `executionControl`:
+
+```xml
+
+
+
+ ...
+
+
+
+
+
+
+
+
+
+
+```
+
+Please notice `skipValue` attribute. It denotes value which forces skipped execution.
+Read `propertyName="skipTests" skipValue="true"` as if property skipTests has value true, plugin will skip execution If
+you declare such value incremental maven will reuse appropriate full-build though technically they are different, but
+because full-build is better it is safe to reuse
+
+### How to renormalize line endings in working copy after committing .gitattributes (git 2.16+)
+
+Ensure you've committed (and ideally pushed everything) - no changes in working copy. After that:
+
+```shell
+# Rewrite objects and update index
+git add --renormalize .
+# Commit changes
+git commit -m "Normalizing line endings"
+# Remove working copy paths from git cache
+git rm --cached -r .
+# Refresh with new line endings
+git reset --hard
+```
+
+### I want to cache interim build and override it later with final version
+
+Solution: set `-Dremote.cache.save.final=true` to nodes which produce final builds. Such builds will not be overridden
+and eventually will replace all interim builds
\ No newline at end of file
diff --git a/Documentation/CACHE-PARAMETERS.md b/Documentation/CACHE-PARAMETERS.md
new file mode 100644
index 000000000000..7633ddbea158
--- /dev/null
+++ b/Documentation/CACHE-PARAMETERS.md
@@ -0,0 +1,52 @@
+
+
+# Overview
+
+This documents contains various configuration parameters supported by cache engine
+
+## Command line flags
+
+| Parameter | Description | Usage Scenario |
+| ----------- | ----------- | ----------- |
+| `-Dremote.cache.configPath=true/false` | Location of cache configuration file | Cache config is not in default location |
+| `-Dremote.cache.enabled=true/false` | Remote cache and associated features disabled/enabled | To remove noise from logs then remote cache is not available |
+| `-Dremote.cache.save.enabled=true/false` | Remote cache save allowed or not | To designate nodes which allowed to push in remote shared cache |
+| `-Dremote.cache.save.final=true/false` | Is it allowed or not to override produced cache | To ensure that reference build is not overriden by interim build |
+| `-Dremote.cache.failFast=true/false` | Fail on the first module whcih cannot be restored from cache | Remote cache setup/tuning/troubleshooting |
+| `-Dremote.cache.baselineUrl=` | Location of baseline build for comparison | Remote cache setup/tuning/troubleshooting |
+
+## Project level properties
+
+Project level parameters allow overriding global parameters on project level Must be specified as project properties:
+
+```xml
+
+
+ ...
+
+ {*.css}
+
+
+```
+
+| Parameter | Description |
+| ----------------------------- | ----------- |
+| `remote.cache.input.glob` | Project specific glob to select sources. Overrides global glob. |
+| `remote.cache.input` | Property prefix to mark paths which must be additionally scanned for source code. Value of property starting with this prefix will be treated as path relatively to current project/module |
+| `remote.cache.exclude` | Property prefix to mark paths which must be excluded from source code search. Value of property starting with this prefix will be treated as path to current project/module |
+| `remote.cache.processPlugins` | Introspect plugins to find inputs or not. Default is true. |
diff --git a/Documentation/CACHE-REMOTE.md b/Documentation/CACHE-REMOTE.md
new file mode 100644
index 000000000000..f5fe38721d70
--- /dev/null
+++ b/Documentation/CACHE-REMOTE.md
@@ -0,0 +1,249 @@
+
+
+# Overview
+
+This document describes generic approach to cache setup. The process require expertise in maven equivalent to expertise
+required to author and Maven your project build, it implies good knowledge of both Maven and the project. Due to Maven
+model limitation the process is manual, but allows you to achieve sufficient control and transparency over caching
+logic.
+
+# Step-By-Step
+
+## Fork branch for cache setup purposes
+
+It is recommended to fork branch for cache setup purposes as you might need to do changes to project build as long as
+you go.
+
+## Setup http server to store artifacts
+
+In order to share build results you need shared storage. Basically any http server which supports http PUT/GET/HEAD
+operations will work. In our case it is a Nginx OSS with file system module. Add the url to config and
+change `remote@enabled` to true:
+
+```xml
+
+
+ http://your-buildcache-url
+
+```
+
+Known limitations: auth is not supported yet
+
+## Build selection
+
+In order to share build results, you need a golden source of builds. Build stored in cache ideally should be a build
+assembled in the most correct, comprehensive and complete way. In such a case you can make sure that whoever reuses such
+build doesn't compromise quality of own build. Often per pull requests builds are the best candidates to populate cache
+because they seed cache fast and provide sufficient quality safeguards.
+
+## CI Build setup to seed shared cache
+
+In order to share build results, you need to store builds in the shared storage. Default scheme is to configure
+designated CI nodes only to push in cache and prohibit elsewhere. In order to allow writes in remote cache add jvm
+property to designated CI builds.
+
+```
+-Dremote.cache.save.enabled=true
+```
+
+Run your branch, review log and ensure that artifacts are uploaded to remote cache. Now, rerun build and ensure that it
+completes almost instantly because it is fully cached. Hint: consider limiting first attempts to single agent/node to
+simplify troubleshooting.
+
+## Normalize local builds to reuse CI build cache
+
+As practice shows, developers often don't realize that builds they run in local and CI environments are different. So
+straightforward attempt to reuse remote cache in local build usually results in cache misses because of difference in
+plugins, parameters, profiles, environment, etc. In order to reuse results you might need to change poms, cache config,
+CI jobs and the project itself. This part is usually most challenging and time-consuming. Follow steps below to
+iteratively achieve working configuration.
+
+### Before you start
+
+Before you start, please keep in mind basic principles:
+
+* Cache is checksum based, it is a complex hash function essentially. In order to to produce the same hash the source
+ code, effective poms and dependencies should match.
+* There is no built-in normalization of line endings in this implementation, file checksum calculation is raw bytes
+ based. The most obvious implication could be illustrated by a simple Git checkout. By default git will check out
+ source code with CRLF line endings on win and LF on Linux. Because of that builds over same commit on a Linux agent
+ and local build on Windows workstation will yield different checksums.
+* Parameters of plugins are manually tracked ony. For example to avoid of accidentally reusing builds which never run
+ tests ensure that critical surfire parameters are tracked (`skipTests` and similar) in config. The same applies for
+ all over plugins.
+
+### Configure local build in debug mode
+
+To minimize distractions and simplify understanding of discrepancies following is recommended:
+
+* Run build with single threaded builder to make sure logs from different modules do not interfere
+* Enable cache fail fast mode to focus on the blocking failure
+* Provide reference to the CI build as a baseline for comparison between your local and remote builds. Go to the
+ reference CI build and one of the final lines of the build should be
+
+```
+[INFO] [CACHE][artifactId] Saved to remote cache https://your-cache-url/<...>/915296a3-4596-4eb5-bf37-f6e13ebe087e/cache-report.xml.
+```
+
+followed by a link to a `cache-report.xml` file. The `cache-report.xml` contains aggregated information about the
+produced cache and could be used as a baseline for comparison.
+
+* Run local build. Command line should look similar to this:
+
+```bash
+mvnw verify -Dremote.cache.failFast=true -Dremote.cache.baselineUrl=https://url-from-ci-build-to-cache-report.xml
+```
+
+Once discrepancy between remote and local builds detected cache will fail with diagnostic info
+in `target/incremental-maven` directory:
+
+```
+* buildinfo-baseline-3c64673e23259e6f.xml - build specficiation from baseline build
+* buildinfo-db43936e0666ce7.xml - build specification of locall build
+* buildsdiff.xml - comparison report with list of discrepancies
+```
+
+Review `buildsdiff.xml` file and eliminate detected discrepancies.You can also diff build-info files directly to get low
+level insights. See techniques to configure cache in [How-To](CACHE-HOWTO.md) and troubleshooting of typical issues in
+the section below.
+
+# Common issues
+
+## Issue 1: Local checkout is with different line endings
+
+Solution: normalise line endings. Current implementation doesn't have built-in line endings normalization, it has to be
+done externally. In git it is recommended to use `.gitattributes` file to establish consistent line endings across all
+envs for file types specific to this project
+
+## Issue 2: Effective poms mismatch because of plugins filtering by profiles
+
+Different profiles between remote and local builds results in different text of effective poms and break checksums.
+Solution: instead of adding/removing specific plugins from build altogether with profiles use profile specific `skip`
+or `disabled` flags instead. Instead of:
+
+ ```
+
+
+ run-plugin-in-ci-only
+
+
+
+ surefire-report-maven-plugin
+
+
+
+
+
+
+
+
+ ```
+
+Use:
+
+ ```xml
+
+
+
+ true
+
+
+
+
+ maven-surefire-plugin
+
+
+ ${skip.plugin.property}
+
+
+
+
+
+
+ run-plugin-in-ci-only
+
+
+ false
+
+
+
+ ```
+
+Hint: effective poms could be found in `buildinfo` files under `/build/projectsInputInfo/item[@type='pom']`
+xpath (`item type="pom"`).
+
+## Issue 3: Effective pom mismatch because of environment specific properties
+
+Potential reason: Sometimes it is not possible to avoid discrepancies in different environments - for example if you
+need to invoke command line command, it will be likely different on win and linux. Such commands will appear in
+effective pom as a different literal values and will result in checksum mismatch Solution: filter out such properties
+from cache effective pom:
+
+```xml
+
+
+
+ ...
+
+
+
+ argLine
+
+
+
+```
+
+## Issue 4: Unexpected or transient files in checksum calculation
+
+Potential reasons: plugins or tests emit temporary files (logs and similar) in non-standard locations Solution: adjust
+global exclusions list to filter out unexpected files:
+
+```
+
+ tempfile.out
+
+```
+
+see sample config for exact syntax
+
+## Issue 5: Difference in tracked plugin properties
+
+Tracked property in config means it is critical for determining is build up to date or not. Discrepancies could happen
+for any plugin for a number of reasons. Example: local build is using java target 1.6, remote: 1.8. `buildsdiff.xml`
+will produce something like
+
+```
+
+```
+
+Solution is at your discretion. If the property is tracked, out-of-date status is fair and expected. If you want to
+relax consistency rules in favor of compatibility, remove property from tracked list
+
+## Issue 5: Version changes invalidate effective pom checksum
+
+Current implementation doesn't support version changes between cache entries. It will result in cache invalidation for
+each new version.
+To mitigate the issue please consider migrating off traditional maven release approach - try to use single version id in
+project (eg `MY-PROJECT-LOCAL`). Such approach simplifies git branching workflow significantly.
+
+Deployment of artifacts with specific version from builds with cache is not supported yet.
+
diff --git a/Documentation/CACHE.md b/Documentation/CACHE.md
new file mode 100644
index 000000000000..391becc7b5f7
--- /dev/null
+++ b/Documentation/CACHE.md
@@ -0,0 +1,170 @@
+
+
+## Overview
+
+Idea of Incremental Maven is to specify module inputs and outputs and make them known to standard maven core. This
+allows accurate analysis and determination of out-of-date build artifacts in the build dependencies graph. Making the
+dependency graph analysis deterministic leads to improvements in build times by avoiding re-building unnecessary
+modules.
+Cache does not make any low-level interventions to build process and delegates actual build work to maven core. This
+guarantees that build results are identical to results produced by standard maven and are fully reproducible.
+To achieve accurate input and outputs calculation incremental maven combines automatic introspection
+of [project object model](https://maven.apache.org/pom.html#What_is_the_POM) in conjunction with configuration-driven
+rules for fine-grained content and execution control. For content analysis it digests based approach which is more
+reliable over widely used file timestamps in tools like Make or Apache Ant. Deterministic build state allows reliably
+cache even intermediate outputs of build and share them between teams using remote cache. Deterministic inputs
+calculation allows distributed and parallel builds running in heterogeneous environments (like cloud of build agents)
+could efficiently reuse cached build artifacts. Therefore incremental maven is particularly well-suited for large maven
+projects that have significant number of small modules. Remote cache in conjunction with precise input identification
+effectively enables "change once - build once" approach.
+
+### Maven insights
+
+The challenge of implementing build cache in Maven is that domain model is overly generic and doesn't support well
+reproducible builds. You might have never thought of that, but it is a reality that 2 different Maven builds from the
+same source code normally produce 2 different results. The question here is tolerance level - can you accept particular
+discrepancies or not. For most of teams artifacts produced in the same build environment from the same source code will
+be considered equivalent and technical differences between them (like different timestamps in jar manifests) could be
+ignored. Now consider scenario when artifact is first produced with compiler X and cached but later without touching a
+update compiler changes to Y and yields significantly different outcomes of compilation. Ask yourself a question \- am I
+consider artifacts of such builds equivalent? Both Yes and No outcomes are pretty possible and could be even desirable
+in different scenarios. When productivity and performance are the primary concerns it could be desirable to tolerate
+insignificant discrepancies and maximise reuse of cached builds. As long as correctness in focus there could be demand
+to comply with the exact release process. In the same way as with classic Maven, decision stays with you - what is
+acceptable difference between builds. In the same way as with classic Maven the previous build is just an approximation
+of today build with some tolerance (implementation, configuration and environment driven).
+
+### Implementation insights
+
+At very simple form, the incremental maven is essentially a hash function which takes maven project and produces hash
+code (checksum). Then hash value is used to fetch and restore build result.
+As with any hash, there could be collisions and instabilities. Collision could happen if the same hash produced from the
+different build states and will result in unintended reuse. Instability means that same input yields different hash sums
+in different runs - resulting in cache miss. The ultimate target is to achieve desired balance between collisions (
+sufficient correctness) and stability (sufficient reuse). In current implementation this is achieved by configuring
+project specific processing rules in static configuration file. To avoid unintentional collisions and achieve better
+correctness need to ensure that every critical file and plugin parameter accounted in build inputs. In order to achieve
+better reuse need to ensure that non-critical files (test logs, readme and similar) and non-critical plugin parameters (
+like number of threads in build) are filtered out from build inputs. Essentially cache configuration is a process of
+inspecting build, taking these decision and reflect them in the cache configuration.
+
+Please notice though idea of perfectly matching builds might be tempting, but it is not practical with regard to
+caching. Perfect correctness means that not a single build could be reused and renders whole idea of builds caching
+useless. Whatever build tool you use, there will be always a tradeoff which might be acceptable or not in particular
+situation. Incremental Maven provides flexible and transparent control over caching policy and allows achieving desired
+outcomes - maximize reusability or maximize equivalence between pre-cached candidates and requested builds.
+
+## Usage
+
+Cornerstone principle of using this tool is that it is delivered as is. Though the tool went through thorough
+verification it's still consumer's responsibility to verify final product quality.
+
+### Recommended Scenarios
+
+Given all the information above, the Incremental Maven is recommended to use in scenarios when productivity and
+performance are in priority. Typical cases are:
+
+* Speedup CI. In conjunction with remote cache incremental maven could drastically reduce build times, validate pull
+ requests faster and reduce load on CI nodes
+* Speedup developer builds. By reusing cached builds developers could verify changes much faster and be more productive.
+ No more `-DskipTests` and similar.
+* Assemble artifacts faster. In some development models it might be critical to have as fast build/deploy cycle as
+ possible. Caching helps to cut down time drastically in such scenarios because it doesn't require to build cached
+ dependencies.
+
+For cases there correctness must be ensured (eg prod builds), it is recommended to disable cache and do clean builds.
+This also allows you to validate cache correctness and reconcile cache outcomes on CI process.
+
+## Getting Started
+
+To on-board incremental maven you need to complete several steps:
+
+* Get incremental maven distribution
+* Add cache config in .mvn
+* Validate build results and iteratively adjust config to project specifics
+* Migrate CI to incremental maven with remote cache (to get full benefit) - optional
+
+### Get incremental maven distribution
+
+The recommended way is to add [Takari Maven Wrapper](https://github.com/takari/maven-wrapper) to your project. In that
+case `maven-wrapper.properties` should reference the latest incremental maven distribution:
+
+```properties
+distributionUrl=https://your-server/maven-incremental.zip
+wrapperUrl=https://your-server/maven-wrapper-0.5.5.jar
+```
+
+Benefits of using maven wrapper are following:
+
+* simple distribution across workstations and CI envs
+* maven stays compatible to your branch
+* further upgrades are simplified significantly
+ If you refuse wrapper - then download, unzip and install it just as usual maven. Further it will be assumed you use
+ maven wrapper (`mvnw`)
+
+### Adding cache config
+
+Copy [default config](maven-cache-config.xml) and [xml schema](../maven-core/src/main/resources/cache-config.xsd)
+to [.mvn](https://maven.apache.org/configure.html) dir of yor project.
+To get overall understanding of cache machinery it is recommended to review the config and read comments. In typical
+scenario you need to adjust:
+
+* remote cache location
+* source code files glob
+* plugins reconciliation rules - add critical plugin parameters to reconciliation
+* add non-standard source code locations (most of locations discovered automatically from project and plugins config,
+ but still there might be edge cases)
+
+See also:
+
+* [Remote cache setup](CACHE-REMOTE.md) - instruction how to setup shared cache
+* [Cache How-To](CACHE-HOWTO.md) - cookbook for frequently encountered questions
+* [Cache Parameters](CACHE-PARAMETERS.md) - description of supported parameters
+* Attached [sample config file](maven-cache-config.xml) and elements annotations in xsd schema. (Ctrl+Q in idea should
+ show annotations in popup)
+
+### Adjusting cache config
+
+Having incremental maven and the config in place you're all set. To run first cacheable build just
+execute: `mvnw clean install`
+
+* Ensure that the config is picked up and incremental maven is picked up. Just check log output - you will notice cache
+ related output or initialization error message.
+* Navigate to your local repo directory - there should be sibling next to your local repo named `cache`
+* Find `buildinfo.xml` for typical module and review it. Ensure that
+ * expected source code files are present in build info
+ * all critical plugins and their critical parameters are covered by config
+
+Notice - in configuration you should find best working trade-off between fairness and cache efficiency. Adding
+unnecessary rules and checks could reduce both performance and cache efficiency (hit rate).
+
+### Adding caching CI and remote cache
+
+To leverage remote cache feature you need web server which supports get/put operations
+like [Nginx OSS](http://nginx.org/en/) (with fs module) or binary repo in Artifactory. It is recommended to populate
+remote cache from CI build. Benefits are:
+
+* such scheme provides predictable and consistent artifacts in remote cache
+* usually CI builds project fast enough to populate cache for team members See [Remote cache setup](CACHE-REMOTE.md) for
+ detailed description of cache setup
+
+## Credits
+CacheConfigImpl
+* Maximilian Novikov - Project lead. Idea, design, coordination and verification.
+* Alexander Ashitkin - Co-design and implementation of the majority of functionality
+* Alexander Novoselov - Hashing module implementation
\ No newline at end of file
diff --git a/Documentation/maven-cache-config.xml b/Documentation/maven-cache-config.xml
new file mode 100644
index 000000000000..a2a7ad8ee1c3
--- /dev/null
+++ b/Documentation/maven-cache-config.xml
@@ -0,0 +1,102 @@
+
+
+
+
+
+ true
+ SHA-256
+ true
+
+ PROJECT-LOCAL
+
+
+ http://host:port
+
+
+ 3
+
+
+
+
+
+
+ {*.java,*.groovy,*.yaml,*.svcd,*.proto,*assembly.xml,assembly*.xml,*logback.xml,*.vm,*.ini,*.jks,*.properties,*.sh,*.bat}
+
+ src/
+ pom.xml
+
+
+
+ 111
+
+
+
+
+
+
+
+ 1
+ 2
+
+
+
+
+
+
+
+
+
+
+ my-execution-id
+
+
+ install
+
+
+ deploy
+
+
+ deploy-local
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index 0c77dabf55ae..88b0a333f257 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,11 @@ build, reporting and documentation from a central piece of information.
If you think you have found a bug, please file an issue in the [Maven Issue Tracker](https://issues.apache.org/jira/browse/MNG).
+Incremental Build and Cache
+-------------
+This maven version supports Incremental Build feature which calculates out-of-date modules in the build dependencies graph and improves build times by avoiding re-building unnecessary modules.
+Read [cache guide](Documentation/CACHE.md) for more details
+
Documentation
-------------
diff --git a/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm b/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
index b589e36e0222..7182bea25132 100644
--- a/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
+++ b/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
@@ -25,6 +25,7 @@ subject to the terms and conditions of the following licenses:
#set ( $apacheMavenGroupIds = [ "org.apache.maven", "org.apache.maven.wagon", "org.apache.maven.resolver",
"org.apache.maven.shared" ] )
#set ( $MITLicenseNames = [ "MIT License", "MIT license", "The MIT License" ] )
+#set ( $CDDLLicenseNames = [ "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0", "CDDL/GPLv2+CE", "CDDL 1.1", "GPL2 w/ CPE" ] )
#foreach ( $project in $projects )
#**##foreach ( $license in $project.licenses )
#* *##set ( $groupId = $project.artifact.groupId )
@@ -41,7 +42,7 @@ subject to the terms and conditions of the following licenses:
#* *##set ( $spdx = 'Apache-2.0' )
#* *##else
#* *### unrecognized license will require analysis to know obligations
-#* *##set ( $spdx = 'unrecognized' )
+#* *##set ( $spdx = "unrecognized: $license.name $license.url" )
#* *##end
#* *###
#* *### fix project urls that are wrong in pom
diff --git a/apache-maven/src/main/appended-resources/licenses/EDL-1.0.txt b/apache-maven/src/main/appended-resources/licenses/EDL-1.0.txt
new file mode 100644
index 000000000000..259e0377f30f
--- /dev/null
+++ b/apache-maven/src/main/appended-resources/licenses/EDL-1.0.txt
@@ -0,0 +1,23 @@
+Eclipse Distribution License - v 1.0
+Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided
+that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation and/or other materials provided
+with the distribution.
+- Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse
+or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/apache-maven/src/main/appended-resources/licenses/GPL-3.0.txt b/apache-maven/src/main/appended-resources/licenses/GPL-3.0.txt
new file mode 100644
index 000000000000..e72bfddabc15
--- /dev/null
+++ b/apache-maven/src/main/appended-resources/licenses/GPL-3.0.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
\ No newline at end of file
diff --git a/apache-maven/src/main/appended-resources/licenses/LGPL-3.0.txt b/apache-maven/src/main/appended-resources/licenses/LGPL-3.0.txt
new file mode 100644
index 000000000000..153d416dc8d2
--- /dev/null
+++ b/apache-maven/src/main/appended-resources/licenses/LGPL-3.0.txt
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
\ No newline at end of file
diff --git a/apache-maven/src/main/appended-resources/licenses/MPL-1.1.txt b/apache-maven/src/main/appended-resources/licenses/MPL-1.1.txt
new file mode 100644
index 000000000000..7bcf5c0e2885
--- /dev/null
+++ b/apache-maven/src/main/appended-resources/licenses/MPL-1.1.txt
@@ -0,0 +1,472 @@
+http://www.mozilla.org/MPL/MPL-1.1.html
+
+
+ MOZILLA PUBLIC LICENSE
+ Version 1.1
+
+ ---------------
+
+1. Definitions.
+
+ 1.0.1. "Commercial Use" means distribution or otherwise making the
+ Covered Code available to a third party.
+
+ 1.1. "Contributor" means each entity that creates or contributes to
+ the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the Original
+ Code, prior Modifications used by a Contributor, and the Modifications
+ made by that particular Contributor.
+
+ 1.3. "Covered Code" means the Original Code or Modifications or the
+ combination of the Original Code and Modifications, in each case
+ including portions thereof.
+
+ 1.4. "Electronic Distribution Mechanism" means a mechanism generally
+ accepted in the software development community for the electronic
+ transfer of data.
+
+ 1.5. "Executable" means Covered Code in any form other than Source
+ Code.
+
+ 1.6. "Initial Developer" means the individual or entity identified
+ as the Initial Developer in the Source Code notice required by Exhibit
+ A.
+
+ 1.7. "Larger Work" means a work which combines Covered Code or
+ portions thereof with code not governed by the terms of this License.
+
+ 1.8. "License" means this document.
+
+ 1.8.1. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. "Modifications" means any addition to or deletion from the
+ substance or structure of either the Original Code or any previous
+ Modifications. When Covered Code is released as a series of files, a
+ Modification is:
+ A. Any addition to or deletion from the contents of a file
+ containing Original Code or previous Modifications.
+
+ B. Any new file that contains any part of the Original Code or
+ previous Modifications.
+
+ 1.10. "Original Code" means Source Code of computer software code
+ which is described in the Source Code notice required by Exhibit A as
+ Original Code, and which, at the time of its release under this
+ License is not already Covered Code governed by this License.
+
+ 1.10.1. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by grantor.
+
+ 1.11. "Source Code" means the preferred form of the Covered Code for
+ making modifications to it, including all modules it contains, plus
+ any associated interface definition files, scripts used to control
+ compilation and installation of an Executable, or source code
+ differential comparisons against either the Original Code or another
+ well known, available Covered Code of the Contributor's choice. The
+ Source Code can be in a compressed or archival form, provided the
+ appropriate decompression or de-archiving software is widely available
+ for no charge.
+
+ 1.12. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms of, this
+ License or a future version of this License issued under Section 6.1.
+ For legal entities, "You" includes any entity which controls, is
+ controlled by, or is under common control with You. For purposes of
+ this definition, "control" means (a) the power, direct or indirect,
+ to cause the direction or management of such entity, whether by
+ contract or otherwise, or (b) ownership of more than fifty percent
+ (50%) of the outstanding shares or beneficial ownership of such
+ entity.
+
+2. Source Code License.
+
+ 2.1. The Initial Developer Grant.
+ The Initial Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license, subject to third party intellectual property
+ claims:
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer to use, reproduce,
+ modify, display, perform, sublicense and distribute the Original
+ Code (or portions thereof) with or without Modifications, and/or
+ as part of a Larger Work; and
+
+ (b) under Patents Claims infringed by the making, using or
+ selling of Original Code, to make, have made, use, practice,
+ sell, and offer for sale, and/or otherwise dispose of the
+ Original Code (or portions thereof).
+
+ (c) the licenses granted in this Section 2.1(a) and (b) are
+ effective on the date Initial Developer first distributes
+ Original Code under the terms of this License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: 1) for code that You delete from the Original Code; 2)
+ separate from the Original Code; or 3) for infringements caused
+ by: i) the modification of the Original Code or ii) the
+ combination of the Original Code with other software or devices.
+
+ 2.2. Contributor Grant.
+ Subject to third party intellectual property claims, each Contributor
+ hereby grants You a world-wide, royalty-free, non-exclusive license
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor, to use, reproduce, modify,
+ display, perform, sublicense and distribute the Modifications
+ created by such Contributor (or portions thereof) either on an
+ unmodified basis, with other Modifications, as Covered Code
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or
+ selling of Modifications made by that Contributor either alone
+ and/or in combination with its Contributor Version (or portions
+ of such combination), to make, use, sell, offer for sale, have
+ made, and/or otherwise dispose of: 1) Modifications made by that
+ Contributor (or portions thereof); and 2) the combination of
+ Modifications made by that Contributor with its Contributor
+ Version (or portions of such combination).
+
+ (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+ effective on the date Contributor first makes Commercial Use of
+ the Covered Code.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: 1) for any code that Contributor has deleted from the
+ Contributor Version; 2) separate from the Contributor Version;
+ 3) for infringements caused by: i) third party modifications of
+ Contributor Version or ii) the combination of Modifications made
+ by that Contributor with other software (except as part of the
+ Contributor Version) or other devices; or 4) under Patent Claims
+ infringed by Covered Code in the absence of Modifications made by
+ that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Application of License.
+ The Modifications which You create or to which You contribute are
+ governed by the terms of this License, including without limitation
+ Section 2.2. The Source Code version of Covered Code may be
+ distributed only under the terms of this License or a future version
+ of this License released under Section 6.1, and You must include a
+ copy of this License with every copy of the Source Code You
+ distribute. You may not offer or impose any terms on any Source Code
+ version that alters or restricts the applicable version of this
+ License or the recipients' rights hereunder. However, You may include
+ an additional document offering the additional rights described in
+ Section 3.5.
+
+ 3.2. Availability of Source Code.
+ Any Modification which You create or to which You contribute must be
+ made available in Source Code form under the terms of this License
+ either on the same media as an Executable version or via an accepted
+ Electronic Distribution Mechanism to anyone to whom you made an
+ Executable version available; and if made available via Electronic
+ Distribution Mechanism, must remain available for at least twelve (12)
+ months after the date it initially became available, or at least six
+ (6) months after a subsequent version of that particular Modification
+ has been made available to such recipients. You are responsible for
+ ensuring that the Source Code version remains available even if the
+ Electronic Distribution Mechanism is maintained by a third party.
+
+ 3.3. Description of Modifications.
+ You must cause all Covered Code to which You contribute to contain a
+ file documenting the changes You made to create that Covered Code and
+ the date of any change. You must include a prominent statement that
+ the Modification is derived, directly or indirectly, from Original
+ Code provided by the Initial Developer and including the name of the
+ Initial Developer in (a) the Source Code, and (b) in any notice in an
+ Executable version or related documentation in which You describe the
+ origin or ownership of the Covered Code.
+
+ 3.4. Intellectual Property Matters
+ (a) Third Party Claims.
+ If Contributor has knowledge that a license under a third party's
+ intellectual property rights is required to exercise the rights
+ granted by such Contributor under Sections 2.1 or 2.2,
+ Contributor must include a text file with the Source Code
+ distribution titled "LEGAL" which describes the claim and the
+ party making the claim in sufficient detail that a recipient will
+ know whom to contact. If Contributor obtains such knowledge after
+ the Modification is made available as described in Section 3.2,
+ Contributor shall promptly modify the LEGAL file in all copies
+ Contributor makes available thereafter and shall take other steps
+ (such as notifying appropriate mailing lists or newsgroups)
+ reasonably calculated to inform those who received the Covered
+ Code that new knowledge has been obtained.
+
+ (b) Contributor APIs.
+ If Contributor's Modifications include an application programming
+ interface and Contributor has knowledge of patent licenses which
+ are reasonably necessary to implement that API, Contributor must
+ also include this information in the LEGAL file.
+
+ (c) Representations.
+ Contributor represents that, except as disclosed pursuant to
+ Section 3.4(a) above, Contributor believes that Contributor's
+ Modifications are Contributor's original creation(s) and/or
+ Contributor has sufficient rights to grant the rights conveyed by
+ this License.
+
+ 3.5. Required Notices.
+ You must duplicate the notice in Exhibit A in each file of the Source
+ Code. If it is not possible to put such notice in a particular Source
+ Code file due to its structure, then You must include such notice in a
+ location (such as a relevant directory) where a user would be likely
+ to look for such a notice. If You created one or more Modification(s)
+ You may add your name as a Contributor to the notice described in
+ Exhibit A. You must also duplicate this License in any documentation
+ for the Source Code where You describe recipients' rights or ownership
+ rights relating to Covered Code. You may choose to offer, and to
+ charge a fee for, warranty, support, indemnity or liability
+ obligations to one or more recipients of Covered Code. However, You
+ may do so only on Your own behalf, and not on behalf of the Initial
+ Developer or any Contributor. You must make it absolutely clear than
+ any such warranty, support, indemnity or liability obligation is
+ offered by You alone, and You hereby agree to indemnify the Initial
+ Developer and every Contributor for any liability incurred by the
+ Initial Developer or such Contributor as a result of warranty,
+ support, indemnity or liability terms You offer.
+
+ 3.6. Distribution of Executable Versions.
+ You may distribute Covered Code in Executable form only if the
+ requirements of Section 3.1-3.5 have been met for that Covered Code,
+ and if You include a notice stating that the Source Code version of
+ the Covered Code is available under the terms of this License,
+ including a description of how and where You have fulfilled the
+ obligations of Section 3.2. The notice must be conspicuously included
+ in any notice in an Executable version, related documentation or
+ collateral in which You describe recipients' rights relating to the
+ Covered Code. You may distribute the Executable version of Covered
+ Code or ownership rights under a license of Your choice, which may
+ contain terms different from this License, provided that You are in
+ compliance with the terms of this License and that the license for the
+ Executable version does not attempt to limit or alter the recipient's
+ rights in the Source Code version from the rights set forth in this
+ License. If You distribute the Executable version under a different
+ license You must make it absolutely clear that any terms which differ
+ from this License are offered by You alone, not by the Initial
+ Developer or any Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred by
+ the Initial Developer or such Contributor as a result of any such
+ terms You offer.
+
+ 3.7. Larger Works.
+ You may create a Larger Work by combining Covered Code with other code
+ not governed by the terms of this License and distribute the Larger
+ Work as a single product. In such a case, You must make sure the
+ requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+ If it is impossible for You to comply with any of the terms of this
+ License with respect to some or all of the Covered Code due to
+ statute, judicial order, or regulation then You must: (a) comply with
+ the terms of this License to the maximum extent possible; and (b)
+ describe the limitations and the code they affect. Such description
+ must be included in the LEGAL file described in Section 3.4 and must
+ be included with all distributions of the Source Code. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Application of this License.
+
+ This License applies to code to which the Initial Developer has
+ attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+ 6.1. New Versions.
+ Netscape Communications Corporation ("Netscape") may publish revised
+ and/or new versions of the License from time to time. Each version
+ will be given a distinguishing version number.
+
+ 6.2. Effect of New Versions.
+ Once Covered Code has been published under a particular version of the
+ License, You may always continue to use it under the terms of that
+ version. You may also choose to use such Covered Code under the terms
+ of any subsequent version of the License published by Netscape. No one
+ other than Netscape has the right to modify the terms applicable to
+ Covered Code created under this License.
+
+ 6.3. Derivative Works.
+ If You create or use a modified version of this License (which you may
+ only do in order to apply it to code which is not already Covered Code
+ governed by this License), You must (a) rename Your license so that
+ the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+ "MPL", "NPL" or any confusingly similar phrase do not appear in your
+ license (except to note that your license differs from this License)
+ and (b) otherwise make it clear that Your version of the license
+ contains terms which differ from the Mozilla Public License and
+ Netscape Public License. (Filling in the name of the Initial
+ Developer, Original Code or Contributor in the notice described in
+ Exhibit A shall not of themselves be deemed to be modifications of
+ this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+ COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+ DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+ THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+ IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+ YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+ COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+ OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+ 8.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to cure
+ such breach within 30 days of becoming aware of the breach. All
+ sublicenses to the Covered Code which are properly granted shall
+ survive any termination of this License. Provisions which, by their
+ nature, must remain in effect beyond the termination of this License
+ shall survive.
+
+ 8.2. If You initiate litigation by asserting a patent infringement
+ claim (excluding declatory judgment actions) against Initial Developer
+ or a Contributor (the Initial Developer or Contributor against whom
+ You file such action is referred to as "Participant") alleging that:
+
+ (a) such Participant's Contributor Version directly or indirectly
+ infringes any patent, then any and all rights granted by such
+ Participant to You under Sections 2.1 and/or 2.2 of this License
+ shall, upon 60 days notice from Participant terminate prospectively,
+ unless if within 60 days after receipt of notice You either: (i)
+ agree in writing to pay Participant a mutually agreeable reasonable
+ royalty for Your past and future use of Modifications made by such
+ Participant, or (ii) withdraw Your litigation claim with respect to
+ the Contributor Version against such Participant. If within 60 days
+ of notice, a reasonable royalty and payment arrangement are not
+ mutually agreed upon in writing by the parties or the litigation claim
+ is not withdrawn, the rights granted by Participant to You under
+ Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+ the 60 day notice period specified above.
+
+ (b) any software, hardware, or device, other than such Participant's
+ Contributor Version, directly or indirectly infringes any patent, then
+ any rights granted to You by such Participant under Sections 2.1(b)
+ and 2.2(b) are revoked effective as of the date You first made, used,
+ sold, distributed, or had made, Modifications made by that
+ Participant.
+
+ 8.3. If You assert a patent infringement claim against Participant
+ alleging that such Participant's Contributor Version directly or
+ indirectly infringes any patent where such claim is resolved (such as
+ by license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+
+ 8.4. In the event of termination under Sections 8.1 or 8.2 above,
+ all end user license agreements (excluding distributors and resellers)
+ which have been validly granted by You or any distributor hereunder
+ prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+ DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+ OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+ ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+ CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+ WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+ RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+ PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+ EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+ THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+ The Covered Code is a "commercial item," as that term is defined in
+ 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" and "commercial computer software documentation," as such
+ terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+ C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+ all U.S. Government End Users acquire Covered Code with only those
+ rights set forth herein.
+
+11. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ California law provisions (except to the extent applicable law, if
+ any, provides otherwise), excluding its conflict-of-law provisions.
+ With respect to disputes in which at least one party is a citizen of,
+ or an entity chartered or registered to do business in the United
+ States of America, any litigation relating to this License shall be
+ subject to the jurisdiction of the Federal Courts of the Northern
+ District of California, with venue lying in Santa Clara County,
+ California, with the losing party responsible for costs, including
+ without limitation, court costs and reasonable attorneys' fees and
+ expenses. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly excluded.
+ Any law or regulation which provides that the language of a contract
+ shall be construed against the drafter shall not apply to this
+ License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+ Initial Developer may designate portions of the Covered Code as
+ "Multiple-Licensed". "Multiple-Licensed" means that the Initial
+ Developer permits you to utilize portions of the Covered Code under
+ Your choice of the MPL or the alternative licenses, if any, specified
+ by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+ ``The contents of this file are subject to the Mozilla Public License
+ Version 1.1 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ https://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ License for the specific language governing rights and limitations
+ under the License.
+
+ The Original Code is ______________________________________.
+
+ The Initial Developer of the Original Code is ________________________.
+ Portions created by ______________________ are Copyright (C) ______
+ _______________________. All Rights Reserved.
+
+ Contributor(s): ______________________________________.
+
+ Alternatively, the contents of this file may be used under the terms
+ of the _____ license (the "[___] License"), in which case the
+ provisions of [______] License are applicable instead of those
+ above. If you wish to allow use of your version of this file only
+ under the terms of the [____] License and not to allow others to use
+ your version of this file under the MPL, indicate your decision by
+ deleting the provisions above and replace them with the notice and
+ other provisions required by the [___] License. If you do not delete
+ the provisions above, a recipient may use your version of this file
+ under either the MPL or the [___] License."
+
+ [NOTE: The text of this Exhibit A may differ slightly from the text of
+ the notices in the Source Code files of the Original Code. You should
+ use the text of this Exhibit A rather than the text found in the
+ Original Code Source Code for Your Modifications.]
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index 86aea1ff2319..8f60c1bea85f 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -149,6 +149,32 @@ under the License.
hamcrest-librarytest
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.6
+
+
+ net.openhft
+ zero-allocation-hashing
+ 0.9
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+ 2.3.3
+
+
+ com.sun.xml.bind
+ jaxb-impl
+ 2.3.3
+ runtime
+
+
+ com.github.albfernandez
+ juniversalchardet
+ 2.4.0
+
@@ -169,6 +195,7 @@ under the License.
plugin-manager.txtproject-builder.txtsrc/site/resources/design/**
+ src/main/resources/cache-*
@@ -225,6 +252,26 @@ under the License.
+
+ org.codehaus.mojo
+ jaxb2-maven-plugin
+ 2.5.0
+
+
+ xjc
+
+ xjc
+
+
+
+
+ org.apache.maven.caching.jaxb
+
+ src/main/resources/cache-config.xsd
+ src/main/resources/cache-domain.xsd
+
+
+
diff --git a/maven-core/src/main/java/org/apache/maven/caching/ArtifactsRepository.java b/maven-core/src/main/java/org/apache/maven/caching/ArtifactsRepository.java
new file mode 100644
index 000000000000..65315498c7ff
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/ArtifactsRepository.java
@@ -0,0 +1,42 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.artifact.Artifact;
+import org.apache.maven.caching.jaxb.CacheReportType;
+import org.apache.maven.caching.xml.BuildInfo;
+import org.apache.maven.execution.MavenSession;
+
+import java.io.IOException;
+
+/**
+ * ArtifactsRepository
+ */
+public interface ArtifactsRepository
+{
+
+ BuildInfo findBuild( CacheContext context ) throws IOException;
+
+ void saveBuildInfo( CacheResult cacheResult, BuildInfo buildInfo ) throws IOException;
+
+ void saveArtifactFile( CacheResult cacheResult, Artifact artifact ) throws IOException;
+
+ void saveCacheReport( String buildId, MavenSession session, CacheReportType cacheReport ) throws IOException;
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/CacheContext.java b/maven-core/src/main/java/org/apache/maven/caching/CacheContext.java
new file mode 100644
index 000000000000..569286d8b841
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/CacheContext.java
@@ -0,0 +1,58 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.caching.jaxb.ProjectsInputInfoType;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * CacheContext
+ */
+public class CacheContext
+{
+ private final MavenProject project;
+ private final ProjectsInputInfoType inputInfo;
+ private final MavenSession session;
+
+ public CacheContext( MavenProject project, ProjectsInputInfoType inputInfo, MavenSession session )
+ {
+ this.project = checkNotNull( project );
+ this.inputInfo = checkNotNull( inputInfo );
+ this.session = checkNotNull( session );
+ }
+
+ public MavenProject getProject()
+ {
+ return project;
+ }
+
+ public ProjectsInputInfoType getInputInfo()
+ {
+ return inputInfo;
+ }
+
+ public MavenSession getSession()
+ {
+ return session;
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/CacheController.java b/maven-core/src/main/java/org/apache/maven/caching/CacheController.java
new file mode 100644
index 000000000000..a91c284e2414
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/CacheController.java
@@ -0,0 +1,52 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.execution.MavenSession;
+import org.apache.maven.execution.MojoExecutionEvent;
+import org.apache.maven.lifecycle.internal.ProjectIndex;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.project.MavenProject;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * CacheController
+ */
+public interface CacheController
+{
+
+ CacheResult findCachedBuild( MavenSession session,
+ MavenProject project,
+ ProjectIndex projectIndex,
+ List mojoExecutions );
+
+ boolean restoreProjectArtifacts( CacheResult cacheResult );
+
+ void save( CacheResult cacheResult,
+ List mojoExecutions,
+ Map executionEvents );
+
+ boolean isForcedExecution( MavenProject project, MojoExecution execution );
+
+ void saveCacheReport( MavenSession session );
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/CacheControllerImpl.java b/maven-core/src/main/java/org/apache/maven/caching/CacheControllerImpl.java
new file mode 100644
index 000000000000..ad9d490c6ebb
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/CacheControllerImpl.java
@@ -0,0 +1,942 @@
+package org.apache.maven.caching;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.mutable.MutableBoolean;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.caching.checksum.KeyUtils;
+import org.apache.maven.caching.checksum.MavenProjectInput;
+import org.apache.maven.caching.hash.HashAlgorithm;
+import org.apache.maven.caching.hash.HashFactory;
+import org.apache.maven.caching.jaxb.ArtifactType;
+import org.apache.maven.caching.jaxb.BuildDiffType;
+import org.apache.maven.caching.jaxb.BuildInfoType;
+import org.apache.maven.caching.jaxb.CacheReportType;
+import org.apache.maven.caching.jaxb.CompletedExecutionType;
+import org.apache.maven.caching.jaxb.DigestItemType;
+import org.apache.maven.caching.jaxb.ProjectReportType;
+import org.apache.maven.caching.jaxb.ProjectsInputInfoType;
+import org.apache.maven.caching.jaxb.PropertyNameType;
+import org.apache.maven.caching.jaxb.TrackedPropertyType;
+import org.apache.maven.caching.xml.BuildInfo;
+import org.apache.maven.caching.xml.CacheConfig;
+import org.apache.maven.caching.xml.CacheSource;
+import org.apache.maven.caching.xml.DtoUtils;
+import org.apache.maven.caching.xml.XmlService;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.execution.MojoExecutionEvent;
+import org.apache.maven.lifecycle.internal.ProjectIndex;
+import org.apache.maven.plugin.MavenPluginManager;
+import org.apache.maven.plugin.Mojo;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.descriptor.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+import org.apache.maven.repository.RepositorySystem;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
+import org.codehaus.plexus.util.ReflectionUtils;
+
+import javax.annotation.Nonnull;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.regex.Pattern;
+
+import static java.nio.file.StandardOpenOption.CREATE;
+import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
+import static org.apache.commons.lang3.StringUtils.replace;
+import static org.apache.commons.lang3.StringUtils.split;
+import static org.apache.maven.caching.CacheResult.empty;
+import static org.apache.maven.caching.CacheResult.failure;
+import static org.apache.maven.caching.CacheResult.partialSuccess;
+import static org.apache.maven.caching.CacheResult.rebuilded;
+import static org.apache.maven.caching.CacheResult.success;
+import static org.apache.maven.caching.HttpRepositoryImpl.BUILDINFO_XML;
+import static org.apache.maven.caching.checksum.KeyUtils.getVersionlessProjectKey;
+import static org.apache.maven.caching.checksum.MavenProjectInput.CACHE_IMPLMENTATION_VERSION;
+
+/**
+ * CacheControllerImpl
+ */
+@Component( role = CacheController.class )
+public class CacheControllerImpl implements CacheController
+{
+
+ public static final String FILE_SEPARATOR_SUBST = "_";
+ private static final String GENERATEDSOURCES = "generatedsources";
+ private static final String GENERATEDSOURCES_PREFIX = GENERATEDSOURCES + FILE_SEPARATOR_SUBST;
+ @Requirement
+ private Logger logger;
+
+ @Requirement
+ private MavenPluginManager mavenPluginManager;
+
+ @Requirement
+ private MavenProjectHelper projectHelper;
+
+ @Requirement
+ private LocalArtifactsRepository localCache;
+
+ @Requirement
+ private RemoteArtifactsRepository remoteCache;
+
+ @Requirement
+ private CacheConfig cacheConfig;
+
+ @Requirement
+ private RepositorySystem repoSystem;
+
+ @Requirement
+ private ArtifactHandlerManager artifactHandlerManager;
+
+ @Requirement
+ private XmlService xmlService;
+
+ private final ConcurrentMap artifactDigestByKey = new ConcurrentHashMap<>();
+
+ private final ConcurrentMap cacheResults = new ConcurrentHashMap<>();
+
+ private volatile BuildInfoType.Scm scm;
+
+ @Override
+ @Nonnull
+ public CacheResult findCachedBuild( MavenSession session, MavenProject project, ProjectIndex projectIndex,
+ List mojoExecutions )
+ {
+
+ final String highestRequestPhase = Iterables.getLast( mojoExecutions ).getLifecyclePhase();
+ if ( !ProjectUtils.isLaterPhase( highestRequestPhase, "post-clean" ) )
+ {
+ return empty();
+ }
+
+ logInfo( project, "Attempting to restore project from build cache" );
+
+ ProjectsInputInfoType inputInfo = calculateInput( project, session, projectIndex );
+
+ final CacheContext context = new CacheContext( project, inputInfo, session );
+ // remote build first
+ CacheResult result = findCachedBuild( mojoExecutions, context );
+
+ if ( !result.isSuccess() && result.getContext() != null )
+ {
+
+ logDebug( project, "Remote cache is incomplete or missing, trying local build" );
+
+ CacheResult localBuild = findLocalBuild( mojoExecutions, context );
+
+ if ( localBuild.isSuccess() || ( localBuild.isPartialSuccess() && !result.isPartialSuccess() ) )
+ {
+ result = localBuild;
+ }
+ }
+ cacheResults.put( getVersionlessProjectKey( project ), result );
+
+ return result;
+ }
+
+ private CacheResult findCachedBuild( List mojoExecutions, CacheContext context )
+ {
+ BuildInfo cachedBuild = null;
+ try
+ {
+ cachedBuild = localCache.findBuild( context );
+ return analyzeResult( context, mojoExecutions, cachedBuild );
+ }
+ catch ( Exception e )
+ {
+ logError( context.getProject(), "Cannot read cached build", e );
+ return cachedBuild != null ? failure( cachedBuild, context ) : failure( context );
+ }
+ }
+
+ private CacheResult findLocalBuild( List mojoExecutions, CacheContext context )
+ {
+ BuildInfo localBuild = null;
+ try
+ {
+ localBuild = localCache.findLocalBuild( context );
+ return analyzeResult( context, mojoExecutions, localBuild );
+ }
+ catch ( Exception e )
+ {
+ logError( context.getProject(), "Cannot read local build", e );
+ return localBuild != null ? failure( localBuild, context ) : failure( context );
+ }
+ }
+
+ private CacheResult analyzeResult( CacheContext context, List mojoExecutions, BuildInfo info )
+ {
+
+ try
+ {
+ if ( info != null )
+ {
+
+ final MavenProject project = context.getProject();
+ final ProjectsInputInfoType inputInfo = context.getInputInfo();
+
+ logInfo( project, "Found cached build, restoring from cache " + inputInfo.getChecksum() );
+
+ if ( logger.isDebugEnabled() )
+ {
+ logDebug( project, "Cached build details: " + info.toString() );
+ }
+
+ final String cacheImplementationVersion = info.getCacheImplementationVersion();
+ if ( !CACHE_IMPLMENTATION_VERSION.equals( cacheImplementationVersion ) )
+ {
+ logger.warn(
+ "Maven and cached build implementations mismatch, caching might not work correctly. "
+ + "Implementation version: " + CACHE_IMPLMENTATION_VERSION + ", cached build: "
+ + info.getCacheImplementationVersion() );
+ }
+
+ final List cachedSegment = info.getCachedSegment( mojoExecutions );
+
+ if ( !info.isAllExecutionsPresent( cachedSegment, logger ) )
+ {
+ logInfo( project, "Cached build doesn't contains all requested plugin executions, cannot restore" );
+ return failure( info, context );
+ }
+
+ if ( !isCachedSegmentPropertiesPresent( project, info, cachedSegment ) )
+ {
+ logInfo( project, "Cached build violates cache rules, cannot restore" );
+ return failure( info, context );
+ }
+
+ final String highestRequestPhase = Iterables.getLast( mojoExecutions ).getLifecyclePhase();
+ final String highestCompletedGoal = info.getHighestCompletedGoal();
+ if ( ProjectUtils.isLaterPhase( highestRequestPhase, highestCompletedGoal ) && !canIgnoreMissingSegment(
+ info, mojoExecutions ) )
+ {
+ logInfo( project,
+ "Project restored partially. Highest cached goal: " + highestCompletedGoal + ", requested: "
+ + highestRequestPhase );
+ return partialSuccess( info, context );
+ }
+
+ return success( info, context );
+ }
+ else
+ {
+ logInfo( context.getProject(), "Project is not found in cache" );
+ return empty( context );
+ }
+ }
+ catch ( Exception e )
+ {
+ logger.error( "Failed to restore project", e );
+ localCache.clearCache( context );
+ return empty( context );
+ }
+ }
+
+ private boolean canIgnoreMissingSegment( BuildInfo info, List mojoExecutions )
+ {
+ final List postCachedSegment = info.getPostCachedSegment( mojoExecutions );
+ for ( MojoExecution mojoExecution : postCachedSegment )
+ {
+ if ( !cacheConfig.canIgnore( mojoExecution ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean restoreProjectArtifacts( CacheResult cacheResult )
+ {
+
+ final BuildInfo buildInfo = cacheResult.getBuildInfo();
+ final CacheContext context = cacheResult.getContext();
+ final MavenProject project = context.getProject();
+
+ final ArtifactType artifact = buildInfo.getArtifact();
+ artifact.setVersion( project.getVersion() );
+
+ try
+ {
+ if ( isNotBlank( artifact.getFileName() ) )
+ {
+ // TODO if remote is forced, probably need to refresh or reconcile all files
+ final Path artifactFile = localCache.getArtifactFile( context, cacheResult.getSource(), artifact );
+ if ( !Files.exists( artifactFile ) )
+ {
+ logInfo( project, "Missing file for cached build, cannot restore. File: " + artifactFile );
+ return false;
+ }
+ logDebug( project, "Setting project artifact " + artifact.getArtifactId() + " from: " + artifactFile );
+ project.getArtifact().setFile( artifactFile.toFile() );
+ project.getArtifact().setResolved( true );
+ putChecksum( artifact, context.getInputInfo().getChecksum() );
+ }
+
+ for ( ArtifactType attachedArtifact : buildInfo.getAttachedArtifacts() )
+ {
+ attachedArtifact.setVersion( project.getVersion() );
+ if ( isNotBlank( attachedArtifact.getFileName() ) )
+ {
+ final Path attachedArtifactFile = localCache.getArtifactFile( context, cacheResult.getSource(),
+ attachedArtifact );
+ if ( !Files.exists( attachedArtifactFile ) )
+ {
+ logInfo( project,
+ "Missing file for cached build, cannot restore project. File: "
+ + attachedArtifactFile );
+ project.getArtifact().setFile( null );
+ project.getArtifact().setResolved( false );
+ project.getAttachedArtifacts().clear();
+ return false;
+ }
+ logDebug( project,
+ "Attaching artifact " + artifact.getArtifactId() + " from: " + attachedArtifactFile );
+ if ( StringUtils.startsWith( attachedArtifact.getClassifier(), GENERATEDSOURCES_PREFIX ) )
+ {
+ // generated sources artifact
+ restoreGeneratedSources( attachedArtifact, attachedArtifactFile, project );
+ }
+ else
+ {
+ projectHelper.attachArtifact( project, attachedArtifact.getType(),
+ attachedArtifact.getClassifier(), attachedArtifactFile.toFile() );
+ }
+ putChecksum( attachedArtifact, context.getInputInfo().getChecksum() );
+ }
+ }
+ }
+ catch ( Exception e )
+ {
+ project.getArtifact().setFile( null );
+ project.getArtifact().setResolved( false );
+ project.getAttachedArtifacts().clear();
+ logError( project, "Cannot restore cache, continuing with normal build.", e );
+ return false;
+ }
+
+ return true;
+ }
+
+ private void putChecksum( ArtifactType artifact, String projectChecksum )
+ {
+
+ final DigestItemType projectArtifact = DtoUtils.createdDigestedByProjectChecksum( artifact, projectChecksum );
+ final String dependencyKey = KeyUtils.getArtifactKey( artifact );
+ artifactDigestByKey.put( dependencyKey, projectArtifact );
+
+ if ( !"pom".equals( artifact.getType() ) )
+ {
+ final ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( artifact.getType() );
+ ArtifactType copy = DtoUtils.copy( artifact );
+ copy.setType( artifactHandler.getPackaging() );
+ artifactDigestByKey.put( KeyUtils.getArtifactKey( copy ), projectArtifact );
+ copy.setType( artifactHandler.getExtension() );
+ artifactDigestByKey.put( KeyUtils.getArtifactKey( copy ), projectArtifact );
+ }
+ }
+
+ private ProjectsInputInfoType calculateInput( MavenProject project, MavenSession session,
+ ProjectIndex projectIndex )
+ {
+ try
+ {
+ final MavenProjectInput inputs = new MavenProjectInput( project, session, cacheConfig, projectIndex,
+ artifactDigestByKey, repoSystem, artifactHandlerManager, logger, localCache, remoteCache );
+ return inputs.calculateChecksum( cacheConfig.getHashFactory() );
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( "Failed to calculate checksums for " + project.getArtifactId(), e );
+ }
+ }
+
+ @Override
+ public void save( CacheResult cacheResult, List mojoExecutions,
+ Map executionEvents )
+ {
+
+ CacheContext context = cacheResult.getContext();
+
+ if ( context == null || context.getInputInfo() == null )
+ {
+ logger.info( "Cannot save project in cache, skipping" );
+ return;
+ }
+
+ final MavenProject project = context.getProject();
+ final MavenSession session = context.getSession();
+ try
+ {
+
+ attachGeneratedSources( project );
+ attachOutputs( project );
+
+ final Artifact projectArtifact = project.getArtifact();
+ final HashFactory hashFactory = cacheConfig.getHashFactory();
+ final HashAlgorithm algorithm = hashFactory.createAlgorithm();
+ final ArtifactType projectArtifactDto = artifactDto( project.getArtifact(), algorithm );
+
+ final List attachedArtifacts =
+ project.getAttachedArtifacts() != null ? project.getAttachedArtifacts() : Collections.emptyList();
+ List attachedArtifactDtos = artifactDtos( attachedArtifacts, algorithm );
+
+ List completedExecution = buildExecutionInfo( mojoExecutions, executionEvents );
+
+ final BuildInfo buildInfo = new BuildInfo( session.getGoals(), projectArtifactDto, attachedArtifactDtos,
+ context.getInputInfo(), completedExecution, hashFactory.getAlgorithm() );
+ populateGitInfo( buildInfo, session );
+ buildInfo.getDto().setFinal( cacheConfig.isSaveFinal() );
+ cacheResults.put( getVersionlessProjectKey( project ), rebuilded( cacheResult, buildInfo ) );
+
+ // if package phase presence means new artifacts were packaged
+ if ( project.hasLifecyclePhase( "package" ) )
+ {
+ localCache.beforeSave( context );
+ localCache.saveBuildInfo( cacheResult, buildInfo );
+ if ( projectArtifact.getFile() != null )
+ {
+ localCache.saveArtifactFile( cacheResult, projectArtifact );
+ putChecksum( projectArtifactDto, context.getInputInfo().getChecksum() );
+ }
+ for ( Artifact attachedArtifact : attachedArtifacts )
+ {
+ if ( attachedArtifact.getFile() != null && isOutputArtifact(
+ attachedArtifact.getFile().getName() ) )
+ {
+ localCache.saveArtifactFile( cacheResult, attachedArtifact );
+ }
+ }
+ for ( ArtifactType attachedArtifactDto : attachedArtifactDtos )
+ {
+ putChecksum( attachedArtifactDto, context.getInputInfo().getChecksum() );
+ }
+ }
+ else
+ {
+ localCache.saveBuildInfo( cacheResult, buildInfo );
+ }
+
+ if ( cacheConfig.isBaselineDiffEnabled() )
+ {
+ produceDiffReport( cacheResult, buildInfo );
+ }
+
+ }
+ catch ( Exception e )
+ {
+ try
+ {
+ logger.error( "Failed to save project, cleaning cache. Project: " + project, e );
+ localCache.clearCache( context );
+ }
+ catch ( Exception ex )
+ {
+ logger.error( "Failed to clean cache due to unexpected error:", e );
+ }
+ }
+ }
+
+ public void produceDiffReport( CacheResult cacheResult, BuildInfo buildInfo )
+ {
+ MavenProject project = cacheResult.getContext().getProject();
+ Optional baselineHolder = remoteCache.findBaselineBuild( project );
+ if ( baselineHolder.isPresent() )
+ {
+ BuildInfo baseline = baselineHolder.get();
+ String outputDirectory = project.getBuild().getDirectory();
+ Path reportOutputDir = Paths.get( outputDirectory, "incremental-maven" );
+ logInfo( project, "Saving cache builds diff to: " + reportOutputDir );
+ BuildDiffType diff = new CacheDiff( buildInfo.getDto(), baseline.getDto(), cacheConfig ).compare();
+ try
+ {
+ Files.createDirectories( reportOutputDir );
+ final ProjectsInputInfoType baselineInputs = baseline.getDto().getProjectsInputInfo();
+ final String checksum = baselineInputs.getChecksum();
+ Files.write( reportOutputDir.resolve( "buildinfo-baseline-" + checksum + ".xml" ),
+ xmlService.toBytes( baseline.getDto() ), TRUNCATE_EXISTING, CREATE );
+ Files.write( reportOutputDir.resolve( "buildinfo-" + checksum + ".xml" ),
+ xmlService.toBytes( buildInfo.getDto() ), TRUNCATE_EXISTING, CREATE );
+ Files.write( reportOutputDir.resolve( "buildsdiff-" + checksum + ".xml" ),
+ xmlService.toBytes( diff ), TRUNCATE_EXISTING, CREATE );
+ final Optional pom = CacheDiff.findPom( buildInfo.getDto().getProjectsInputInfo() );
+ if ( pom.isPresent() )
+ {
+ Files.write( reportOutputDir.resolve( "effective-pom-" + checksum + ".xml" ),
+ pom.get().getValue().getBytes( StandardCharsets.UTF_8 ),
+ TRUNCATE_EXISTING, CREATE );
+ }
+ final Optional baselinePom = CacheDiff.findPom( baselineInputs );
+ if ( baselinePom.isPresent() )
+ {
+ Files.write( reportOutputDir.resolve(
+ "effective-pom-baseline-" + baselineInputs.getChecksum() + ".xml" ),
+ baselinePom.get().getValue().getBytes( StandardCharsets.UTF_8 ),
+ TRUNCATE_EXISTING, CREATE );
+ }
+ }
+ catch ( IOException e )
+ {
+ logError( project, "Cannot produce build diff for project", e );
+ }
+ }
+ else
+ {
+ logInfo( project, "Cannot find project in baseline build, skipping diff" );
+ }
+ }
+
+ private List artifactDtos( List attachedArtifacts, HashAlgorithm digest ) throws IOException
+ {
+ List result = new ArrayList<>();
+ for ( Artifact attachedArtifact : attachedArtifacts )
+ {
+ if ( attachedArtifact.getFile() != null && isOutputArtifact( attachedArtifact.getFile().getName() ) )
+ {
+ result.add( artifactDto( attachedArtifact, digest ) );
+ }
+ }
+ return result;
+ }
+
+ private ArtifactType artifactDto( Artifact projectArtifact, HashAlgorithm algorithm ) throws IOException
+ {
+ final ArtifactType dto = DtoUtils.createDto( projectArtifact );
+ if ( projectArtifact.getFile() != null && projectArtifact.getFile().isFile() )
+ {
+ final Path file = projectArtifact.getFile().toPath();
+ dto.setFileHash( algorithm.hash( file ) );
+ dto.setFileSize( BigInteger.valueOf( Files.size( file ) ) );
+ }
+ return dto;
+ }
+
+ private List buildExecutionInfo( List mojoExecutions,
+ Map executionEvents )
+ {
+ List list = new ArrayList<>();
+ for ( MojoExecution mojoExecution : mojoExecutions )
+ {
+ final String executionKey = ProjectUtils.mojoExecutionKey( mojoExecution );
+ final MojoExecutionEvent executionEvent = executionEvents.get( executionKey );
+ CompletedExecutionType executionInfo = new CompletedExecutionType();
+ executionInfo.setExecutionKey( executionKey );
+ executionInfo.setMojoClassName( mojoExecution.getMojoDescriptor().getImplementation() );
+ if ( executionEvent != null )
+ {
+ recordMojoProperties( executionInfo, executionEvent );
+ }
+ list.add( executionInfo );
+ }
+ return list;
+ }
+
+ private void recordMojoProperties( CompletedExecutionType execution, MojoExecutionEvent executionEvent )
+ {
+ final MojoExecution mojoExecution = executionEvent.getExecution();
+
+ final boolean logAll = cacheConfig.isLogAllProperties( mojoExecution );
+ List trackedProperties = cacheConfig.getTrackedProperties( mojoExecution );
+ List noLogProperties = cacheConfig.getNologProperties( mojoExecution );
+ List forceLogProperties = cacheConfig.getLoggedProperties( mojoExecution );
+ final Mojo mojo = executionEvent.getMojo();
+
+ final File baseDir = executionEvent.getProject().getBasedir();
+ final String baseDirPath = FilenameUtils.normalizeNoEndSeparator( baseDir.getAbsolutePath() ) + File.separator;
+
+ final List parameters = mojoExecution.getMojoDescriptor().getParameters();
+ for ( Parameter parameter : parameters )
+ {
+ // editable parameters could be configured by user
+ if ( !parameter.isEditable() )
+ {
+ continue;
+ }
+
+ final String propertyName = parameter.getName();
+ final boolean tracked = isTracked( propertyName, trackedProperties );
+ if ( !tracked && isExcluded( propertyName, logAll, noLogProperties, forceLogProperties ) )
+ {
+ continue;
+ }
+
+ try
+ {
+ final Object value = ReflectionUtils.getValueIncludingSuperclasses( propertyName, mojo );
+ DtoUtils.addProperty( execution, propertyName, value, baseDirPath, tracked );
+ }
+ catch ( IllegalAccessException e )
+ {
+ logInfo( executionEvent.getProject(),
+ "Cannot get property " + propertyName + " value from " + mojo + ": " + e.getMessage() );
+ if ( tracked )
+ {
+ throw new IllegalArgumentException(
+ "Property configured in cache introspection config for " + mojo + " is not accessible: "
+ + propertyName );
+ }
+ }
+ }
+ }
+
+ private boolean isExcluded( String propertyName, boolean logAll, List excludedProperties,
+ List forceLogProperties )
+ {
+
+ if ( !forceLogProperties.isEmpty() )
+ {
+ for ( PropertyNameType logProperty : forceLogProperties )
+ {
+ if ( StringUtils.equals( propertyName, logProperty.getPropertyName() ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if ( !excludedProperties.isEmpty() )
+ {
+ for ( PropertyNameType excludedProperty : excludedProperties )
+ {
+ if ( StringUtils.equals( propertyName, excludedProperty.getPropertyName() ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return !logAll;
+ }
+
+ private boolean isTracked( String propertyName, List trackedProperties )
+ {
+ for ( TrackedPropertyType trackedProperty : trackedProperties )
+ {
+ if ( StringUtils.equals( propertyName, trackedProperty.getPropertyName() ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isCachedSegmentPropertiesPresent( MavenProject project, BuildInfo buildInfo,
+ List mojoExecutions )
+ {
+ for ( MojoExecution mojoExecution : mojoExecutions )
+ {
+
+ // completion of all mojos checked above, so we expect tp have execution info here
+ final List trackedProperties = cacheConfig.getTrackedProperties( mojoExecution );
+ final CompletedExecutionType cachedExecution = buildInfo.findMojoExecutionInfo( mojoExecution );
+
+ if ( cachedExecution == null )
+ {
+ logInfo( project,
+ "Execution is not cached. Plugin: " + mojoExecution.getExecutionId() + ", goal"
+ + mojoExecution.getGoal() );
+ return false;
+ }
+
+ if ( !DtoUtils.containsAllProperties( cachedExecution, trackedProperties ) )
+ {
+ logInfo( project, "Build info doesn't match rules. Plugin: " + mojoExecution.getExecutionId() );
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void logDebug( MavenProject project, String message )
+ {
+ if ( logger.isDebugEnabled() )
+ {
+ logger.debug( "[CACHE][" + project.getArtifactId() + "] " + message );
+ }
+ }
+
+ private void logInfo( MavenProject project, String message )
+ {
+ logger.info( "[CACHE][" + project.getArtifactId() + "] " + message );
+ }
+
+ private void logError( MavenProject project, String message, Exception e )
+ {
+ logger.error( "[CACHE][" + project.getArtifactId() + "] " + message, e );
+ }
+
+ @Override
+ public boolean isForcedExecution( MavenProject project, MojoExecution execution )
+ {
+
+ if ( cacheConfig.isForcedExecution( execution ) )
+ {
+ return true;
+ }
+ final Properties properties = project.getProperties();
+ final String alwaysRunPlugins = properties.getProperty( "remote.cache.alwaysRunPlugins" );
+ ArrayList alwaysRunPluginsList = new ArrayList<>();
+ if ( alwaysRunPlugins != null )
+ {
+ alwaysRunPluginsList = Lists.newArrayList( split( alwaysRunPlugins, "," ) );
+ }
+ for ( String pluginAndGoal : alwaysRunPluginsList )
+ {
+ final String[] tokens = pluginAndGoal.split( ":" );
+ final String alwaysRunPlugin = tokens[0];
+ String alwaysRunGoal = tokens.length == 1 ? "*" : tokens[1];
+ if ( StringUtils.equals( execution.getPlugin().getArtifactId(), alwaysRunPlugin ) && ( "*".equals(
+ alwaysRunGoal ) || StringUtils.equals( execution.getGoal(), alwaysRunGoal ) ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void saveCacheReport( MavenSession session )
+ {
+ try
+ {
+
+ CacheReportType cacheReport = new CacheReportType();
+ for ( CacheResult result : cacheResults.values() )
+ {
+ ProjectReportType projectReport = new ProjectReportType();
+ CacheContext context = result.getContext();
+ MavenProject project = context.getProject();
+ projectReport.setGroupId( project.getGroupId() );
+ projectReport.setArtifactId( project.getArtifactId() );
+ projectReport.setChecksum( context.getInputInfo().getChecksum() );
+ boolean checksumMatched = result.getStatus() != RestoreStatus.EMPTY;
+ projectReport.setChecksumMatched( checksumMatched );
+ projectReport.setLifecycleMatched( checksumMatched && result.isSuccess() );
+ projectReport.setSource( String.valueOf( result.getSource() ) );
+ if ( result.getSource() == CacheSource.REMOTE )
+ {
+ projectReport.setUrl( remoteCache.getResourceUrl( context, BUILDINFO_XML ) );
+ }
+ else if ( result.getSource() == CacheSource.BUILD && cacheConfig.isSaveToRemote() )
+ {
+ projectReport.setSharedToRemote( true );
+ projectReport.setUrl( remoteCache.getResourceUrl( context, BUILDINFO_XML ) );
+ }
+ cacheReport.getProject().add( projectReport );
+ }
+
+ String buildId = UUID.randomUUID().toString();
+ localCache.saveCacheReport( buildId, session, cacheReport );
+ }
+ catch ( Exception e )
+ {
+ logger.error( "Cannot save incremental build aggregated report", e );
+ }
+ }
+
+ private void populateGitInfo( BuildInfo buildInfo, MavenSession session ) throws IOException
+ {
+ if ( scm == null )
+ {
+ synchronized ( this )
+ {
+ if ( scm == null )
+ {
+ try
+ {
+ scm = ProjectUtils.readGitInfo( session );
+ }
+ catch ( IOException e )
+ {
+ scm = new BuildInfoType.Scm();
+ logger.error( "Cannot populate git info", e );
+ }
+ }
+ }
+ }
+ buildInfo.getDto().setScm( scm );
+ }
+
+ private void zipAndAttachArtifact( MavenProject project, Path dir, String classifier ) throws IOException
+ {
+
+ try ( final InputStream inputStream = ZipUtils.zipFolder( dir ) )
+ {
+ File tempFile = File.createTempFile( "maven-incremental", project.getArtifactId() );
+ tempFile.deleteOnExit();
+ Files.copy( inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING );
+ projectHelper.attachArtifact( project, "zip", classifier, tempFile );
+ }
+ }
+
+ private String pathToClassifier( Path relative )
+ {
+ final int nameCount = relative.getNameCount();
+ List segments = new ArrayList<>( nameCount + 1 );
+ for ( int i = 0; i < nameCount; i++ )
+ {
+ segments.add( relative.getName( i ).toFile().getName() );
+ }
+ // todo handle _ in file names
+ return GENERATEDSOURCES_PREFIX + StringUtils.join( segments.iterator(), FILE_SEPARATOR_SUBST );
+ }
+
+ private Path classifierToPath( Path outputDir, String classifier )
+ {
+ classifier = StringUtils.removeStart( classifier, GENERATEDSOURCES_PREFIX );
+ final String relPath = replace( classifier, FILE_SEPARATOR_SUBST, File.separator );
+ return outputDir.resolve( relPath );
+ }
+
+ private void restoreGeneratedSources( ArtifactType artifact, Path artifactFilePath, MavenProject project )
+ throws IOException
+ {
+ final Path targetDir = Paths.get( project.getBuild().getDirectory() );
+ final Path outputDir = classifierToPath( targetDir, artifact.getClassifier() );
+ try ( InputStream is = Files.newInputStream( artifactFilePath ) )
+ {
+ if ( Files.exists( outputDir ) )
+ {
+ FileUtils.cleanDirectory( outputDir.toFile() );
+ }
+ else
+ {
+ Files.createDirectories( outputDir );
+ }
+ ZipUtils.unzip( is, outputDir );
+ }
+ }
+
+ //TODO: move to config
+ public void attachGeneratedSources( MavenProject project ) throws IOException
+ {
+ final Path targetDir = Paths.get( project.getBuild().getDirectory() );
+
+ final Path generatedSourcesDir = targetDir.resolve( "generated-sources" );
+ attachDirIfNotEmpty( generatedSourcesDir, targetDir, project );
+
+ final Path generatedTestSourcesDir = targetDir.resolve( "generated-test-sources" );
+ attachDirIfNotEmpty( generatedTestSourcesDir, targetDir, project );
+
+ Set sourceRoots = new TreeSet<>();
+ if ( project.getCompileSourceRoots() != null )
+ {
+ sourceRoots.addAll( project.getCompileSourceRoots() );
+ }
+ if ( project.getTestCompileSourceRoots() != null )
+ {
+ sourceRoots.addAll( project.getTestCompileSourceRoots() );
+ }
+
+ for ( String sourceRoot : sourceRoots )
+ {
+ final Path sourceRootPath = Paths.get( sourceRoot );
+ if ( Files.isDirectory( sourceRootPath ) && sourceRootPath.startsWith(
+ targetDir ) && !( sourceRootPath.startsWith( generatedSourcesDir ) || sourceRootPath.startsWith(
+ generatedTestSourcesDir ) ) )
+ { // dir within target
+ attachDirIfNotEmpty( sourceRootPath, targetDir, project );
+ }
+ }
+ }
+
+ private void attachOutputs( MavenProject project ) throws IOException
+ {
+ final List attachedDirs = cacheConfig.getAttachedOutputs();
+ for ( String dir : attachedDirs )
+ {
+ final Path targetDir = Paths.get( project.getBuild().getDirectory() );
+ final Path outputDir = targetDir.resolve( dir );
+ attachDirIfNotEmpty( outputDir, targetDir, project );
+ }
+ }
+
+ private void attachDirIfNotEmpty( Path candidateSubDir, Path parentDir, MavenProject project ) throws IOException
+ {
+ if ( Files.isDirectory( candidateSubDir ) && hasFiles( candidateSubDir ) )
+ {
+ final Path relativePath = parentDir.relativize( candidateSubDir );
+ final String classifier = pathToClassifier( relativePath );
+ zipAndAttachArtifact( project, candidateSubDir, classifier );
+ logDebug( project, "Attached directory: " + candidateSubDir );
+ }
+ }
+
+ private boolean hasFiles( Path candidateSubDir ) throws IOException
+ {
+ final MutableBoolean hasFiles = new MutableBoolean();
+ Files.walkFileTree( candidateSubDir, new SimpleFileVisitor()
+ {
+ @Override
+ public FileVisitResult visitFile( Path path, BasicFileAttributes basicFileAttributes )
+ {
+ hasFiles.setTrue();
+ return FileVisitResult.TERMINATE;
+ }
+ } );
+ return hasFiles.booleanValue();
+ }
+
+ private boolean isOutputArtifact( String name )
+ {
+ List excludePatterns = cacheConfig.getExcludePatterns();
+ for ( Pattern pattern : excludePatterns )
+ {
+ if ( pattern.matcher( name ).matches() )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/CacheDiff.java b/maven-core/src/main/java/org/apache/maven/caching/CacheDiff.java
new file mode 100644
index 000000000000..9e066a598eff
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/CacheDiff.java
@@ -0,0 +1,345 @@
+package org.apache.maven.caching;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.caching.jaxb.BuildDiffType;
+import org.apache.maven.caching.jaxb.BuildInfoType;
+import org.apache.maven.caching.jaxb.CompletedExecutionType;
+import org.apache.maven.caching.jaxb.DigestItemType;
+import org.apache.maven.caching.jaxb.MismatchType;
+import org.apache.maven.caching.jaxb.ProjectsInputInfoType;
+import org.apache.maven.caching.jaxb.PropertyValueType;
+import org.apache.maven.caching.xml.CacheConfig;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Utility class for comparing 2 builds
+ */
+public class CacheDiff
+{
+
+ private final CacheConfig config;
+ private final BuildInfoType current;
+ private final BuildInfoType baseline;
+ private final LinkedList report;
+
+ public CacheDiff( BuildInfoType current, BuildInfoType baseline, CacheConfig config )
+ {
+ this.current = current;
+ this.baseline = baseline;
+ this.config = config;
+ this.report = new LinkedList<>();
+ }
+
+ public BuildDiffType compare()
+ {
+
+ if ( !StringUtils.equals( current.getHashFunction(), baseline.getHashFunction() ) )
+ {
+ addNewMismatch(
+ "hashFunction",
+ current.getHashFunction(),
+ baseline.getHashFunction(),
+ "Different algorithms render caches not comparable and cached could not be reused",
+ "Ensure the same algorithm as remote"
+ );
+ }
+ compareEffectivePoms( current.getProjectsInputInfo(), baseline.getProjectsInputInfo() );
+ compareExecutions( current.getExecutions(), baseline.getExecutions() );
+ compareFiles( current.getProjectsInputInfo(), baseline.getProjectsInputInfo() );
+ compareDependencies( current.getProjectsInputInfo(), baseline.getProjectsInputInfo() );
+
+ final BuildDiffType buildDiffType = new BuildDiffType();
+ buildDiffType.getMismatch().addAll( report );
+ return buildDiffType;
+ }
+
+ private void compareEffectivePoms( ProjectsInputInfoType current, ProjectsInputInfoType baseline )
+ {
+ Optional currentPom = findPom( current );
+ String currentPomHash = currentPom.isPresent() ? currentPom.get().getHash() : null;
+
+ Optional baseLinePom = findPom( baseline );
+ String baselinePomHash = baseLinePom.isPresent() ? baseLinePom.get().getHash() : null;
+
+ if ( !StringUtils.equals( currentPomHash, baselinePomHash ) )
+ {
+ addNewMismatch(
+ "effectivePom", currentPomHash, baselinePomHash,
+ "Difference in effective pom suggests effectively different builds which cannot be reused",
+ "Compare raw content of effective poms and eliminate differences. "
+ + "See How-To for common techniques"
+ );
+ }
+ }
+
+ public static Optional findPom( ProjectsInputInfoType projectInputs )
+ {
+ for ( DigestItemType digestItemType : projectInputs.getItem() )
+ {
+ if ( "pom".equals( digestItemType.getType() ) )
+ {
+ return Optional.of( digestItemType );
+
+ }
+ }
+ return Optional.absent();
+ }
+
+ private void compareFiles( ProjectsInputInfoType current, ProjectsInputInfoType baseline )
+ {
+
+ final Map currentFiles = new HashMap<>();
+ for ( DigestItemType item : current.getItem() )
+ {
+ if ( "file".equals( item.getType() ) )
+ {
+ currentFiles.put( item.getValue(), item );
+ }
+ }
+
+ final Map baselineFiles = new HashMap<>();
+ for ( DigestItemType item : baseline.getItem() )
+ {
+ if ( "file".equals( item.getType() ) )
+ {
+ baselineFiles.put( item.getValue(), item );
+ }
+ }
+
+ final Sets.SetView currentVsBaseline = Sets.difference( currentFiles.keySet(), baselineFiles.keySet() );
+ final Sets.SetView baselineVsCurrent = Sets.difference( baselineFiles.keySet(), currentFiles.keySet() );
+
+ if ( !currentVsBaseline.isEmpty() || !baselineVsCurrent.isEmpty() )
+ {
+ addNewMismatch( "source files",
+ "Remote and local cache contain different sets of input files. "
+ + "Added files: " + currentVsBaseline + ". Removed files: " + baselineVsCurrent,
+ "To match remote and local caches should have identical file sets."
+ + " Unnecessary and transient files must be filtered out to make file sets match"
+ + " - see configuration guide"
+ );
+ return;
+ }
+
+ for ( Map.Entry entry : currentFiles.entrySet() )
+ {
+ String filePath = entry.getKey();
+ DigestItemType currentFile = entry.getValue();
+ // should be null safe because sets are compared above for differences
+ final DigestItemType baselineFile = baselineFiles.get( filePath );
+ if ( !StringUtils.equals( currentFile.getHash(), baselineFile.getHash() ) )
+ {
+
+ String reason = "File content is different.";
+ if ( currentFile.getEol() != null && baselineFile.getEol() != null && !StringUtils.equals(
+ baselineFile.getEol(), currentFile.getEol() ) )
+ {
+ reason += " Different line endings detected (text files relevant). "
+ + "Remote: " + baselineFile.getEol() + ", local: " + currentFile.getEol() + ".";
+ }
+ if ( currentFile.getCharset() != null && baselineFile.getCharset() != null && !StringUtils.equals(
+ baselineFile.getCharset(), currentFile.getCharset() ) )
+ {
+ reason += " Different charset detected (text files relevant). "
+ + "Remote: " + baselineFile.getEol() + ", local: " + currentFile.getEol() + ".";
+ }
+
+ addNewMismatch( filePath, currentFile.getHash(), baselineFile.getHash(), reason,
+ "Different content manifests different build outcome. "
+ + "Ensure that difference is not caused by environment specifics, like line separators"
+ );
+ }
+ }
+ }
+
+ private void compareDependencies( ProjectsInputInfoType current, ProjectsInputInfoType baseline )
+ {
+ final Map currentDependencies = new HashMap<>();
+ for ( DigestItemType digestItemType : current.getItem() )
+ {
+ if ( "dependency".equals( digestItemType.getType() ) )
+ {
+ currentDependencies.put( digestItemType.getValue(), digestItemType );
+ }
+ }
+ final Map baselineDependencies = new HashMap<>();
+ for ( DigestItemType item : baseline.getItem() )
+ {
+ if ( "dependency".equals( item.getType() ) )
+ {
+ baselineDependencies.put( item.getValue(), item );
+ }
+ }
+
+ final Sets.SetView currentVsBaseline =
+ Sets.difference( currentDependencies.keySet(), baselineDependencies.keySet() );
+ final Sets.SetView baselineVsCurrent =
+ Sets.difference( baselineDependencies.keySet(), currentDependencies.keySet() );
+
+ if ( !currentVsBaseline.isEmpty() || !baselineVsCurrent.isEmpty() )
+ {
+ addNewMismatch( "dependencies files",
+ "Remote and local builds contain different sets of dependencies and cannot be matched. "
+ + "Added dependencies: " + currentVsBaseline + ". Removed dependencies: "
+ + baselineVsCurrent,
+ "Remote and local builds should have identical dependencies. "
+ + "The difference manifests changes in downstream dependencies or introduced snapshots."
+ );
+ return;
+ }
+
+ for ( Map.Entry entry : currentDependencies.entrySet() )
+ {
+ String dependencyKey = entry.getKey();
+ DigestItemType currentDependency = entry.getValue();
+ // null safe - sets compared for differences above
+ final DigestItemType baselineDependency = baselineDependencies.get( dependencyKey );
+ if ( !StringUtils.equals( currentDependency.getHash(), baselineDependency.getHash() ) )
+ {
+ addNewMismatch( dependencyKey, currentDependency.getHash(), baselineDependency.getHash(),
+ "Downstream project or snapshot changed",
+ "Find downstream project and investigate difference in the downstream project. "
+ + "Enable fail fast mode and single threaded execution to simplify debug."
+ );
+ }
+ }
+ }
+
+
+ private void compareExecutions( BuildInfoType.Executions current, BuildInfoType.Executions baseline )
+ {
+ Map baselineExecutionsByKey = new HashMap<>();
+ for ( CompletedExecutionType completedExecutionType : baseline.getExecution() )
+ {
+ baselineExecutionsByKey.put( completedExecutionType.getExecutionKey(), completedExecutionType );
+ }
+
+ Map currentExecutionsByKey = new HashMap<>();
+ for ( CompletedExecutionType e1 : current.getExecution() )
+ {
+ currentExecutionsByKey.put( e1.getExecutionKey(), e1 );
+ }
+
+ // such situation normally means different poms and mismatch in effective poms,
+ // but in any case it is helpful to report
+ for ( CompletedExecutionType baselineExecution : baseline.getExecution() )
+ {
+ if ( !currentExecutionsByKey.containsKey( baselineExecution.getExecutionKey() ) )
+ {
+ addNewMismatch(
+ baselineExecution.getExecutionKey(),
+ "Baseline build contains excessive plugin " + baselineExecution.getExecutionKey(),
+ "Different set of plugins produces different build results. "
+ + "Exclude non-critical plugins or make sure plugin sets match"
+ );
+ }
+ }
+
+ for ( CompletedExecutionType currentExecution : current.getExecution() )
+ {
+ if ( !baselineExecutionsByKey.containsKey( currentExecution.getExecutionKey() ) )
+ {
+ addNewMismatch(
+ currentExecution.getExecutionKey(),
+ "Cached build doesn't contain plugin " + currentExecution.getExecutionKey(),
+ "Different set of plugins produces different build results. "
+ + "Filter out non-critical plugins or make sure remote cache always run full build "
+ + "with all plugins"
+ );
+ continue;
+ }
+
+ final CompletedExecutionType baselineExecution =
+ baselineExecutionsByKey.get( currentExecution.getExecutionKey() );
+ comparePlugins( currentExecution, baselineExecution );
+ }
+ }
+
+ private void comparePlugins( CompletedExecutionType current, CompletedExecutionType baseline )
+ {
+ // TODO add support for skip values
+ final List trackedProperties = new ArrayList<>();
+ for ( PropertyValueType propertyValueType : current.getConfiguration().getProperty() )
+ {
+ if ( propertyValueType.isTracked() )
+ {
+ trackedProperties.add( propertyValueType );
+ }
+ }
+ if ( trackedProperties.isEmpty() )
+ {
+ return;
+ }
+
+ final Map baselinePropertiesByName = new HashMap<>();
+ for ( PropertyValueType propertyValueType : baseline.getConfiguration().getProperty() )
+ {
+ baselinePropertiesByName.put( propertyValueType.getName(), propertyValueType );
+ }
+
+ for ( PropertyValueType p : trackedProperties )
+ {
+ final PropertyValueType baselineValue = baselinePropertiesByName.get( p.getName() );
+ if ( baselineValue == null || !StringUtils.equals( baselineValue.getValue(), p.getValue() ) )
+ {
+ addNewMismatch(
+ p.getName(),
+ p.getValue(),
+ baselineValue == null ? null : baselineValue.getValue(),
+ "Plugin: " + current.getExecutionKey()
+ + " has mismatch in tracked property and cannot be reused",
+ "Align properties between remote and local build or remove property from tracked "
+ + "list if mismatch could be tolerated. In some cases it is possible to add skip value "
+ + "to ignore lax mismatch"
+ );
+ }
+ }
+ }
+
+ private void addNewMismatch( String item, String current, String baseline, String reason,
+ String resolution )
+ {
+ final MismatchType mismatch = new MismatchType();
+ mismatch.setItem( item );
+ mismatch.setCurrent( current );
+ mismatch.setBaseline( baseline );
+ mismatch.setReason( reason );
+ mismatch.setResolution( resolution );
+ report.add( mismatch );
+ }
+
+ private void addNewMismatch( String property, String reason, String resolution )
+ {
+ final MismatchType mismatchType = new MismatchType();
+ mismatchType.setItem( property );
+ mismatchType.setReason( reason );
+ mismatchType.setResolution( resolution );
+ report.add( mismatchType );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/CacheEventSpy.java b/maven-core/src/main/java/org/apache/maven/caching/CacheEventSpy.java
new file mode 100644
index 000000000000..99f7e1a72542
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/CacheEventSpy.java
@@ -0,0 +1,49 @@
+package org.apache.maven.caching; /* * 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. */ /* * 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. */
+
+/*
+ * 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.eventspy.AbstractEventSpy;
+import org.apache.maven.eventspy.EventSpy;
+import org.apache.maven.execution.ExecutionEvent;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+
+/**
+ * Triggers cache report generation on build completion
+ */
+@Component( role = EventSpy.class )
+public class CacheEventSpy extends AbstractEventSpy
+{
+ @Requirement
+ private CacheController cacheController;
+
+ @Override
+ public void onEvent( Object event ) throws Exception
+ {
+ if ( event instanceof ExecutionEvent )
+ {
+ ExecutionEvent executionEvent = (ExecutionEvent) event;
+ if ( executionEvent.getType() == ExecutionEvent.Type.SessionEnded )
+ {
+ cacheController.saveCacheReport( executionEvent.getSession() );
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/maven-core/src/main/java/org/apache/maven/caching/CacheResult.java b/maven-core/src/main/java/org/apache/maven/caching/CacheResult.java
new file mode 100644
index 000000000000..8d886764f8b8
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/CacheResult.java
@@ -0,0 +1,122 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.caching.xml.BuildInfo;
+import org.apache.maven.caching.xml.CacheSource;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * CacheResult
+ */
+public class CacheResult
+{
+ private final RestoreStatus status;
+ private final BuildInfo buildInfo;
+ private final CacheContext context;
+
+ private CacheResult( RestoreStatus status, BuildInfo buildInfo, CacheContext context )
+ {
+ this.status = requireNonNull( status );
+ this.buildInfo = buildInfo;
+ this.context = context;
+ }
+
+ public static CacheResult empty( CacheContext context )
+ {
+ requireNonNull( context );
+ return new CacheResult( RestoreStatus.EMPTY, null, context );
+ }
+
+ public static CacheResult empty()
+ {
+ return new CacheResult( RestoreStatus.EMPTY, null, null );
+ }
+
+ public static CacheResult failure( BuildInfo buildInfo, CacheContext context )
+ {
+ requireNonNull( buildInfo );
+ requireNonNull( context );
+ return new CacheResult( RestoreStatus.FAILURE, buildInfo, context );
+ }
+
+ public static CacheResult success( BuildInfo buildInfo, CacheContext context )
+ {
+ requireNonNull( buildInfo );
+ requireNonNull( context );
+ return new CacheResult( RestoreStatus.SUCCESS, buildInfo, context );
+ }
+
+ public static CacheResult partialSuccess( BuildInfo buildInfo, CacheContext context )
+ {
+ requireNonNull( buildInfo );
+ requireNonNull( context );
+ return new CacheResult( RestoreStatus.PARTIAL, buildInfo, context );
+ }
+
+ public static CacheResult failure( CacheContext context )
+ {
+ requireNonNull( context );
+ return new CacheResult( RestoreStatus.FAILURE, null, context );
+ }
+
+ public static CacheResult rebuilded( CacheResult orig, BuildInfo buildInfo )
+ {
+ requireNonNull( orig );
+ requireNonNull( buildInfo );
+ return new CacheResult( orig.status, buildInfo, orig.context );
+ }
+
+ public boolean isSuccess()
+ {
+ return status == RestoreStatus.SUCCESS;
+ }
+
+ public BuildInfo getBuildInfo()
+ {
+ return buildInfo;
+ }
+
+ public CacheSource getSource()
+ {
+ return buildInfo != null ? buildInfo.getSource() : null;
+ }
+
+ public CacheContext getContext()
+ {
+ return context;
+ }
+
+ public boolean isPartialSuccess()
+ {
+ return status == RestoreStatus.PARTIAL;
+ }
+
+ public RestoreStatus getStatus()
+ {
+ return status;
+ }
+
+ public boolean isFinal()
+ {
+ return buildInfo != null && buildInfo.getDto().isFinal();
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/Clock.java b/maven-core/src/main/java/org/apache/maven/caching/Clock.java
new file mode 100644
index 000000000000..ce0c487c669c
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/Clock.java
@@ -0,0 +1,42 @@
+package org.apache.maven.caching;
+
+/*
+ * 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 java.util.concurrent.TimeUnit.NANOSECONDS;
+
+/**
+ * Clock
+ */
+public class Clock
+{
+ public static long time()
+ {
+ return System.nanoTime();
+ }
+
+ public static long elapsed( long time )
+ {
+ return NANOSECONDS.toMillis( time() - time );
+ }
+
+ private Clock()
+ {
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/DefaultPluginScanConfig.java b/maven-core/src/main/java/org/apache/maven/caching/DefaultPluginScanConfig.java
new file mode 100644
index 000000000000..408d097cf10e
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/DefaultPluginScanConfig.java
@@ -0,0 +1,63 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.caching.jaxb.DirScanConfigType;
+
+import javax.annotation.Nonnull;
+
+/**
+ * DefaultPluginScanConfig
+ */
+public class DefaultPluginScanConfig implements PluginScanConfig
+{
+
+ @Override
+ public boolean isSkip()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean accept( String propertyName )
+ {
+ return true;
+ }
+
+ @Override
+ @Nonnull
+ public PluginScanConfig mergeWith( PluginScanConfig overrideSource )
+ {
+ return overrideSource;
+ }
+
+ @Nonnull
+ @Override
+ public ScanConfigProperties getTagScanProperties( String tagName )
+ {
+ return new ScanConfigProperties( true, "*" );
+ }
+
+ @Override
+ public DirScanConfigType dto()
+ {
+ return null;
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/HttpRepositoryImpl.java b/maven-core/src/main/java/org/apache/maven/caching/HttpRepositoryImpl.java
new file mode 100644
index 000000000000..fbbe509bb28d
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/HttpRepositoryImpl.java
@@ -0,0 +1,336 @@
+package org.apache.maven.caching;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.caching.checksum.MavenProjectInput;
+import org.apache.maven.caching.jaxb.ArtifactType;
+import org.apache.maven.caching.jaxb.BuildInfoType;
+import org.apache.maven.caching.jaxb.CacheReportType;
+import org.apache.maven.caching.jaxb.ProjectReportType;
+import org.apache.maven.caching.xml.BuildInfo;
+import org.apache.maven.caching.xml.CacheConfig;
+import org.apache.maven.caching.xml.CacheSource;
+import org.apache.maven.caching.xml.XmlService;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.LegacySupport;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * HttpRepositoryImpl
+ */
+@Component( role = RemoteArtifactsRepository.class )
+public class HttpRepositoryImpl implements RemoteArtifactsRepository
+{
+
+ public static final String BUILDINFO_XML = "buildinfo.xml";
+ public static final String CACHE_REPORT_XML = "cache-report.xml";
+
+ @Requirement
+ private Logger logger;
+
+ @Requirement
+ LegacySupport legacySupport;
+
+ @Requirement
+ XmlService xmlService;
+
+ @Requirement
+ private CacheConfig cacheConfig;
+
+ @SuppressWarnings( {"checkstyle:constantname", "checkstyle:magicnumber"} )
+ private static final ThreadLocal httpClient = new ThreadLocal()
+ {
+ @Override
+ protected HttpClient initialValue()
+ {
+ int timeoutSeconds = 60;
+ RequestConfig config = RequestConfig.custom().setConnectTimeout(
+ timeoutSeconds * 1000 ).setConnectionRequestTimeout( timeoutSeconds * 1000 ).setSocketTimeout(
+ timeoutSeconds * 1000 ).build();
+ return HttpClientBuilder.create().setDefaultRequestConfig( config ).build();
+ }
+ };
+
+ @Override
+ public BuildInfo findBuild( CacheContext context )
+ {
+ final String resourceUrl = getResourceUrl( context, BUILDINFO_XML );
+ String artifactId = context.getProject().getArtifactId();
+ if ( exists( artifactId, resourceUrl ) )
+ {
+ final byte[] bytes = getResourceContent( resourceUrl, artifactId );
+ final BuildInfoType dto = xmlService.fromBytes( BuildInfoType.class, bytes );
+ return new BuildInfo( dto, CacheSource.REMOTE );
+ }
+ return null;
+ }
+
+ @Override
+ public byte[] getArtifactContent( CacheContext context, ArtifactType artifact )
+ {
+ return getResourceContent( getResourceUrl( context, artifact.getFileName() ),
+ context.getProject().getArtifactId() );
+ }
+
+ @Override
+ public void saveBuildInfo( CacheResult cacheResult, BuildInfo buildInfo ) throws IOException
+ {
+ CacheContext context = cacheResult.getContext();
+ final String resourceUrl = getResourceUrl( cacheResult.getContext(), BUILDINFO_XML );
+ putToRemoteCache( new ByteArrayInputStream( xmlService.toBytes( buildInfo.getDto() ) ), resourceUrl,
+ context.getProject().getArtifactId() );
+ }
+
+
+ @Override
+ public void saveCacheReport( String buildId, MavenSession session, CacheReportType cacheReport ) throws IOException
+ {
+ MavenProject rootProject = session.getTopLevelProject();
+ final String resourceUrl = cacheConfig.getUrl() + "/" + MavenProjectInput.CACHE_IMPLMENTATION_VERSION
+ + "/" + rootProject.getGroupId()
+ + "/" + rootProject.getArtifactId()
+ + "/" + buildId
+ + "/" + CACHE_REPORT_XML;
+ putToRemoteCache( new ByteArrayInputStream( xmlService.toBytes( cacheReport ) ), resourceUrl,
+ rootProject.getArtifactId() );
+ }
+
+ @Override
+ public void saveArtifactFile( CacheResult cacheResult, Artifact artifact ) throws IOException
+ {
+ CacheContext context = cacheResult.getContext();
+ final String resourceUrl = getResourceUrl( cacheResult.getContext(), ProjectUtils.normalizedName( artifact ) );
+ try ( InputStream inputStream = Files.newInputStream( artifact.getFile().toPath() ) )
+ {
+ putToRemoteCache( inputStream, resourceUrl, context.getProject().getArtifactId() );
+ }
+ }
+
+ @SuppressWarnings( "checkstyle:magicnumber" )
+ private boolean exists( String logReference, String url )
+ {
+ HttpHead head = null;
+ try
+ {
+ head = new HttpHead( url );
+ HttpResponse response = httpClient.get().execute( head );
+ int statusCode = response.getStatusLine().getStatusCode();
+ logger.info( "[CACHE][" + logReference + "] Checking " + url + ". Status: " + statusCode );
+ return statusCode == 200;
+ }
+ catch ( IOException e )
+ {
+ throw new RuntimeException( "Cannot check " + url, e );
+ }
+ finally
+ {
+ if ( head != null )
+ {
+ head.releaseConnection();
+ }
+ }
+ }
+
+ @SuppressWarnings( "checkstyle:magicnumber" )
+ public byte[] getResourceContent( String url, String logReference )
+ {
+ HttpGet get = null;
+ try
+ {
+ get = new HttpGet( url );
+ HttpResponse response = httpClient.get().execute( get );
+ int statusCode = response.getStatusLine().getStatusCode();
+ logger.info( "[CACHE][" + logReference + "] Downloading " + url + ". Status: " + statusCode );
+ if ( statusCode != 200 )
+ {
+ throw new RuntimeException( "Cannot download " + url + ", unexpected status code: " + statusCode );
+ }
+ try ( InputStream content = response.getEntity().getContent() )
+ {
+ return IOUtils.toByteArray( content );
+ }
+ }
+ catch ( IOException e )
+ {
+ throw new RuntimeException( "Cannot get " + url, e );
+ }
+ finally
+ {
+ if ( get != null )
+ {
+ get.releaseConnection();
+ }
+ }
+ }
+
+ @Override
+ public String getResourceUrl( CacheContext context, String filename )
+ {
+ return getResourceUrl( filename, context.getProject().getGroupId(), context.getProject().getArtifactId(),
+ context.getInputInfo().getChecksum() );
+ }
+
+ private String getResourceUrl( String filename, String groupId, String artifactId, String checksum )
+ {
+ return cacheConfig.getUrl() + "/" + MavenProjectInput.CACHE_IMPLMENTATION_VERSION + "/" + groupId + "/"
+ + artifactId + "/" + checksum + "/" + filename;
+ }
+
+ /**
+ * @param logReference
+ * @param instream to be closed externally
+ */
+ private void putToRemoteCache( InputStream instream, String url, String logReference ) throws IOException
+ {
+
+ HttpPut httpPut = null;
+ try
+ {
+ httpPut = new HttpPut( url );
+ httpPut.setEntity( new InputStreamEntity( instream ) );
+ HttpResponse response = httpClient.get().execute( httpPut );
+ int statusCode = response.getStatusLine().getStatusCode();
+ logInfo( "Saved to remote cache " + url + ". RESPONSE CODE: " + statusCode, logReference );
+ }
+ finally
+ {
+ if ( httpPut != null )
+ {
+ httpPut.releaseConnection();
+ }
+ }
+ }
+
+ private final AtomicReference>> cacheReportSupplier = new AtomicReference<>();
+
+ @Override
+ public Optional findBaselineBuild( MavenProject project )
+ {
+ final Optional> cachedProjectsHolder = findCacheInfo()
+ .transform( CacheReportType::getProject );
+ if ( !cachedProjectsHolder.isPresent() )
+ {
+ return Optional.absent();
+ }
+
+ Optional cachedProjectHolder = Optional.absent();
+ for ( ProjectReportType p : cachedProjectsHolder.get() )
+ {
+ if ( project.getArtifactId().equals( p.getArtifactId() ) && project.getGroupId().equals(
+ p.getGroupId() ) )
+ {
+ cachedProjectHolder = Optional.of( p );
+ break;
+ }
+ }
+
+ if ( cachedProjectHolder.isPresent() )
+ {
+ String url;
+ final ProjectReportType projectReport = cachedProjectHolder.get();
+ if ( projectReport.isSetUrl() )
+ {
+ url = cachedProjectHolder.get().getUrl();
+ logInfo( "Retrieving baseline buildinfo: " + projectReport.getUrl(), project.getArtifactId() );
+ }
+ else
+ {
+ url = getResourceUrl( BUILDINFO_XML, project.getGroupId(),
+ project.getArtifactId(), projectReport.getChecksum() );
+ logInfo( "Baseline project record doesn't have url, trying default location", project.getArtifactId() );
+ }
+
+ try
+ {
+ if ( exists( project.getArtifactId(), url ) )
+ {
+ byte[] content = getResourceContent( url, project.getArtifactId() );
+ final BuildInfoType dto = xmlService.fromBytes( BuildInfoType.class, content );
+ return Optional.of( new BuildInfo( dto, CacheSource.REMOTE ) );
+ }
+ else
+ {
+ logInfo( "Project buildinfo not found, skipping diff",
+ project.getArtifactId() );
+ }
+ }
+ catch ( Exception e )
+ {
+ logger.warn( "[CACHE][" + project.getArtifactId() + "] Error restoring baseline build at url: "
+ + projectReport.getUrl() + ", skipping diff" );
+ return Optional.absent();
+ }
+ }
+ return Optional.absent();
+ }
+
+ private Optional findCacheInfo()
+ {
+
+ Supplier> candidate = Suppliers.memoize( () ->
+ {
+ try
+ {
+ logInfo( "Downloading baseline cache report from: " + cacheConfig.getBaselineCacheUrl(),
+ "DEBUG" );
+ byte[] content = getResourceContent( cacheConfig.getBaselineCacheUrl(), "cache-info" );
+ CacheReportType cacheReportType = xmlService.fromBytes( CacheReportType.class, content );
+ return Optional.of( cacheReportType );
+ }
+ catch ( Exception e )
+ {
+ logger.error( "Error downloading baseline report from: " + cacheConfig.getBaselineCacheUrl()
+ + ", skipping diff.", e );
+ return Optional.absent();
+ }
+ } );
+ cacheReportSupplier.compareAndSet( null, candidate );
+
+ return cacheReportSupplier.get().get();
+ }
+
+ private void logInfo( String message, String logReference )
+ {
+ logger.info( "[CACHE][" + logReference + "] " + message );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/LocalArtifactsRepository.java b/maven-core/src/main/java/org/apache/maven/caching/LocalArtifactsRepository.java
new file mode 100644
index 000000000000..c5916b2c64ba
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/LocalArtifactsRepository.java
@@ -0,0 +1,47 @@
+package org.apache.maven.caching;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.base.Optional;
+import org.apache.maven.caching.jaxb.ArtifactType;
+import org.apache.maven.caching.xml.BuildInfo;
+import org.apache.maven.caching.xml.CacheSource;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Dependency;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+/**
+ * LocalArtifactsRepository
+ */
+public interface LocalArtifactsRepository extends ArtifactsRepository
+{
+
+ void beforeSave( CacheContext environment ) throws IOException;
+
+ Path getArtifactFile( CacheContext context, CacheSource source, ArtifactType artifact ) throws IOException;
+
+ void clearCache( CacheContext context );
+
+ Optional findBestMatchingBuild( MavenSession session, Dependency dependency ) throws IOException;
+
+ BuildInfo findLocalBuild( CacheContext context ) throws IOException;
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/LocalRepositoryImpl.java b/maven-core/src/main/java/org/apache/maven/caching/LocalRepositoryImpl.java
new file mode 100644
index 000000000000..ec75b476e4b4
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/LocalRepositoryImpl.java
@@ -0,0 +1,496 @@
+package org.apache.maven.caching;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Ordering;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.caching.jaxb.ArtifactType;
+import org.apache.maven.caching.jaxb.BuildInfoType;
+import org.apache.maven.caching.jaxb.CacheReportType;
+import org.apache.maven.caching.xml.BuildInfo;
+import org.apache.maven.caching.xml.CacheConfig;
+import org.apache.maven.caching.xml.CacheSource;
+import org.apache.maven.caching.xml.XmlService;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.plugin.LegacySupport;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+
+import static java.nio.file.StandardOpenOption.CREATE;
+import static java.nio.file.StandardOpenOption.CREATE_NEW;
+import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
+import static java.util.concurrent.TimeUnit.DAYS;
+import static java.util.concurrent.TimeUnit.HOURS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
+import static org.apache.maven.caching.ProjectUtils.getMultimoduleRoot;
+import static org.apache.maven.caching.checksum.MavenProjectInput.CACHE_IMPLMENTATION_VERSION;
+
+/**
+ * LocalRepositoryImpl
+ */
+@Component( role = LocalArtifactsRepository.class )
+public class LocalRepositoryImpl implements LocalArtifactsRepository
+{
+
+ private static final String BUILDINFO_XML = "buildinfo.xml";
+ private static final String LOOKUPINFO_XML = "lookupinfo.xml";
+ private static final long ONE_HOUR_MILLIS = HOURS.toMillis( 1 );
+ private static final long ONE_MINUTE_MILLIS = MINUTES.toMillis( 1 );
+ private static final long ONE_DAY_MILLIS = DAYS.toMillis( 1 );
+ private static final String EMPTY = "";
+ private static final LastModifiedComparator LAST_MODIFIED_COMPARATOR = new LastModifiedComparator();
+ private static final Function, Long> GET_LAST_MODIFIED =
+ pair -> pair.getRight().lastModified();
+
+ @Requirement
+ private Logger logger;
+
+ @Requirement
+ private LegacySupport legacySupport;
+
+ @Requirement
+ private RemoteArtifactsRepository remoteRepository;
+
+ @Requirement
+ private XmlService xmlService;
+
+ @Requirement
+ private CacheConfig cacheConfig;
+
+ private final LoadingCache, Optional> bestBuildCache =
+ CacheBuilder.newBuilder().build(
+ CacheLoader.from( new Function, Optional>()
+ {
+ @Override
+ public Optional apply( Pair input )
+ {
+ try
+ {
+ return findBestMatchingBuildImpl( input );
+ }
+ catch ( IOException e )
+ {
+ logger.error( "Cannot find dependency in cache", e );
+ return Optional.absent();
+ }
+ }
+ } ) );
+
+ @Override
+ public BuildInfo findLocalBuild( CacheContext context ) throws IOException
+ {
+ Path localBuildInfoPath = localBuildPath( context, BUILDINFO_XML, false );
+ logDebug( context, "Checking local build info: " + localBuildInfoPath );
+ if ( Files.exists( localBuildInfoPath ) )
+ {
+ logInfo( context, "Local build found by checksum " + context.getInputInfo().getChecksum() );
+ try
+ {
+ final BuildInfoType dto = xmlService.fromFile( BuildInfoType.class, localBuildInfoPath.toFile() );
+ return new BuildInfo( dto, CacheSource.LOCAL );
+ }
+ catch ( Exception e )
+ {
+ logger.error( "Local build info is not valid, deleting: " + localBuildInfoPath, e );
+ Files.delete( localBuildInfoPath );
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public BuildInfo findBuild( CacheContext context ) throws IOException
+ {
+
+ Path buildInfoPath = remoteBuildPath( context, BUILDINFO_XML );
+ logDebug( context, "Checking if build is already downloaded: " + buildInfoPath );
+
+ if ( Files.exists( buildInfoPath ) )
+ {
+ logInfo( context, "Downloaded build found by checksum " + context.getInputInfo().getChecksum() );
+ try
+ {
+ final BuildInfoType dto = xmlService.fromFile( BuildInfoType.class, buildInfoPath.toFile() );
+ return new BuildInfo( dto, CacheSource.REMOTE );
+ }
+ catch ( Exception e )
+ {
+ logger.error( "Downloaded build info is not valid, deleting: " + buildInfoPath, e );
+ Files.delete( buildInfoPath );
+ }
+ }
+
+ if ( !cacheConfig.isRemoteCacheEnabled() )
+ {
+ return null;
+ }
+
+ try
+ {
+
+ Path lookupInfoPath = remoteBuildPath( context, LOOKUPINFO_XML );
+ if ( Files.exists( lookupInfoPath ) )
+ {
+ final BasicFileAttributes fileAttributes = Files.readAttributes( lookupInfoPath,
+ BasicFileAttributes.class );
+ final long lastModified = fileAttributes.lastModifiedTime().toMillis();
+ final long created = fileAttributes.creationTime().toMillis();
+ final long now = System.currentTimeMillis();
+ // throttle remote cache calls, maven like
+ if ( now < created + ONE_HOUR_MILLIS && now < lastModified + ONE_MINUTE_MILLIS )
+ { // fresh file, allow lookup every minute
+ logInfo( context, "Skipping remote lookup, last unsuccessful lookup less than 1m ago." );
+ return null;
+ }
+ else if ( now < created + ONE_DAY_MILLIS && now < lastModified + ONE_HOUR_MILLIS )
+ { // less than 1 day file, allow 1 per hour lookup
+ logInfo( context, "Skipping remote lookup, last unsuccessful lookup less than 1h ago." );
+ return null;
+ }
+ else if ( now > created + ONE_DAY_MILLIS && now < lastModified + ONE_DAY_MILLIS )
+ { // more than 1 day file, allow 1 per day lookup
+ logInfo( context, "Skipping remote lookup, last unsuccessful lookup less than 1d ago." );
+ return null;
+ }
+ }
+
+ final BuildInfo buildInfo = remoteRepository.findBuild( context );
+ if ( buildInfo != null )
+ {
+ logInfo( context, "Build info downloaded from remote repo, saving to: " + buildInfoPath );
+ Files.createDirectories( buildInfoPath.getParent() );
+ Files.write( buildInfoPath, xmlService.toBytes( buildInfo.getDto() ), CREATE_NEW );
+ }
+ else
+ {
+ FileUtils.touch( lookupInfoPath.toFile() );
+ }
+ return buildInfo;
+ }
+ catch ( Exception e )
+ {
+ logger.error( "Remote build info is not valid, cached data is not compatible", e );
+ return null;
+ }
+ }
+
+ @Override
+ public void clearCache( CacheContext context )
+ {
+ try
+ {
+ final Path buildCacheDir = buildCacheDir( context );
+ Path artifactCacheDir = buildCacheDir.getParent();
+
+ if ( !Files.exists( artifactCacheDir ) )
+ {
+ return;
+ }
+
+ List cacheDirs = new ArrayList<>();
+ for ( Path dir : Files.newDirectoryStream( artifactCacheDir ) )
+ {
+ if ( Files.isDirectory( dir ) )
+ {
+ cacheDirs.add( dir );
+ }
+ }
+ if ( cacheDirs.size() > cacheConfig.getMaxLocalBuildsCached() )
+ {
+ Collections.sort( cacheDirs, LAST_MODIFIED_COMPARATOR );
+ for ( Path dir : cacheDirs.subList( 0, cacheDirs.size() - cacheConfig.getMaxLocalBuildsCached() ) )
+ {
+ FileUtils.deleteDirectory( dir.toFile() );
+ }
+ }
+ final Path path = localBuildDir( context );
+ if ( Files.exists( path ) )
+ {
+ FileUtils.deleteDirectory( path.toFile() );
+ }
+ }
+ catch ( IOException e )
+ {
+ final String artifactId = context.getProject().getArtifactId();
+ throw new RuntimeException(
+ "Failed to cleanup local cache of " + artifactId + " on build failure, it might be inconsistent",
+ e );
+ }
+ }
+
+ @Override
+ public Optional findBestMatchingBuild( MavenSession session, Dependency dependency )
+ {
+ return bestBuildCache.getUnchecked( Pair.of( session, dependency ) );
+ }
+
+
+ private Optional findBestMatchingBuildImpl( Pair dependencySession )
+ throws IOException
+ {
+ final MavenSession session = dependencySession.getLeft();
+ final Dependency dependency = dependencySession.getRight();
+
+ final Path artifactCacheDir = artifactCacheDir( session, dependency.getGroupId(), dependency.getArtifactId() );
+
+ final Multimap, Pair> filesByVersion = ArrayListMultimap.create();
+
+ Files.walkFileTree( artifactCacheDir, new SimpleFileVisitor()
+ {
+ @Override
+ public FileVisitResult visitFile( Path o, BasicFileAttributes basicFileAttributes )
+ {
+ final File file = o.toFile();
+ if ( file.getName().equals( BUILDINFO_XML ) )
+ {
+ try
+ {
+ final BuildInfoType dto = xmlService.fromFile( BuildInfoType.class, file );
+ final Pair buildInfoAndFile = Pair.of( new BuildInfo( dto, CacheSource.LOCAL ),
+ file );
+ final String cachedVersion = dto.getArtifact().getVersion();
+ final String cachedBranch = getScmRef( dto.getScm() );
+ filesByVersion.put( Pair.of( cachedVersion, cachedBranch ), buildInfoAndFile );
+ if ( isNotBlank( cachedBranch ) )
+ {
+ filesByVersion.put( Pair.of( EMPTY, cachedBranch ), buildInfoAndFile );
+ }
+ if ( isNotBlank( cachedVersion ) )
+ {
+ filesByVersion.put( Pair.of( cachedVersion, EMPTY ), buildInfoAndFile );
+ }
+ }
+ catch ( Exception e )
+ {
+ // version is unusable nothing we can do here
+ logger.error( "Build info is not compatible to current maven implementation: " + file );
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ } );
+
+ if ( filesByVersion.isEmpty() )
+ {
+ return Optional.absent();
+ }
+
+ final String currentRef = getScmRef( ProjectUtils.readGitInfo( session ) );
+ // first lets try by branch and version
+ Collection> bestMatched = new LinkedList<>();
+ if ( isNotBlank( currentRef ) )
+ {
+ bestMatched = filesByVersion.get( Pair.of( dependency.getVersion(), currentRef ) );
+ }
+ if ( Iterables.isEmpty( bestMatched ) )
+ {
+ // then by version
+ bestMatched = filesByVersion.get( Pair.of( dependency.getVersion(), EMPTY ) );
+ }
+ if ( Iterables.isEmpty( bestMatched ) && isNotBlank( currentRef ) )
+ {
+ // then by branch
+ bestMatched = filesByVersion.get( Pair.of( EMPTY, currentRef ) );
+ }
+ if ( Iterables.isEmpty( bestMatched ) )
+ {
+ // ok lets take all
+ bestMatched = filesByVersion.values();
+ }
+
+ List> orderedFiles = Ordering.natural().onResultOf(
+ GET_LAST_MODIFIED ).reverse().sortedCopy( bestMatched );
+ return Optional.of( orderedFiles.get( 0 ).getLeft() );
+ }
+
+ private String getScmRef( BuildInfoType.Scm scm )
+ {
+ if ( scm != null )
+ {
+ return scm.isSetSourceBranch() ? scm.getSourceBranch() : scm.getRevision();
+ }
+ else
+ {
+ return EMPTY;
+ }
+ }
+
+ @Override
+ public Path getArtifactFile( CacheContext context, CacheSource source, ArtifactType artifact ) throws IOException
+ {
+ if ( source == CacheSource.LOCAL )
+ {
+ return localBuildPath( context, artifact.getFileName(), false );
+ }
+ else
+ {
+ Path cachePath = remoteBuildPath( context, artifact.getFileName() );
+ if ( !Files.exists( cachePath ) && cacheConfig.isRemoteCacheEnabled() )
+ {
+ final byte[] artifactContent = remoteRepository.getArtifactContent( context, artifact );
+ if ( artifactContent != null )
+ {
+ Files.write( cachePath, artifactContent, CREATE_NEW );
+ }
+ }
+ return cachePath;
+ }
+ }
+
+ @Override
+ public void beforeSave( CacheContext environment )
+ {
+ clearCache( environment );
+ }
+
+ @Override
+ public void saveBuildInfo( CacheResult cacheResult, BuildInfo buildInfo ) throws IOException
+ {
+ final Path path = localBuildPath( cacheResult.getContext(), BUILDINFO_XML, true );
+ Files.write( path, xmlService.toBytes( buildInfo.getDto() ), TRUNCATE_EXISTING, CREATE );
+ if ( cacheConfig.isRemoteCacheEnabled() && cacheConfig.isSaveToRemote() && !cacheResult.isFinal() )
+ {
+ remoteRepository.saveBuildInfo( cacheResult, buildInfo );
+ }
+ }
+
+ @Override
+ public void saveCacheReport( String buildId, MavenSession session, CacheReportType cacheReport ) throws IOException
+ {
+ Path path = Paths.get( getMultimoduleRoot( session ), "target", "maven-incremental" );
+ Files.createDirectories( path );
+ Files.write( path.resolve( "cache-report." + buildId + ".xml" ), xmlService.toBytes( cacheReport ),
+ TRUNCATE_EXISTING, CREATE );
+ if ( cacheConfig.isRemoteCacheEnabled() && cacheConfig.isSaveToRemote() )
+ {
+ logger.info( "[CACHE] Saving cache report on build completion" );
+ remoteRepository.saveCacheReport( buildId, session, cacheReport );
+ }
+ }
+
+ @Override
+ public void saveArtifactFile( CacheResult cacheResult, Artifact artifact ) throws IOException
+ {
+ // safe artifacts to cache
+ File artifactFile = artifact.getFile();
+ Path cachePath = localBuildPath( cacheResult.getContext(), ProjectUtils.normalizedName( artifact ), true );
+ Files.copy( artifactFile.toPath(), cachePath, StandardCopyOption.REPLACE_EXISTING );
+ if ( cacheConfig.isRemoteCacheEnabled() && cacheConfig.isSaveToRemote() && !cacheResult.isFinal() )
+ {
+ remoteRepository.saveArtifactFile( cacheResult, artifact );
+ }
+ }
+
+ private Path buildCacheDir( CacheContext context ) throws IOException
+ {
+ final MavenProject project = context.getProject();
+ final Path artifactCacheDir = artifactCacheDir( context.getSession(), project.getGroupId(),
+ project.getArtifactId() );
+ return artifactCacheDir.resolve( context.getInputInfo().getChecksum() );
+ }
+
+ private Path artifactCacheDir( MavenSession session, String groupId, String artifactId ) throws IOException
+ {
+ final String localRepositoryRoot = session.getLocalRepository().getBasedir();
+ final Path path = Paths.get( localRepositoryRoot, "..", "cache", CACHE_IMPLMENTATION_VERSION, groupId,
+ artifactId ).normalize();
+ if ( !Files.exists( path ) )
+ {
+ Files.createDirectories( path );
+ }
+ return path;
+ }
+
+ private Path remoteBuildPath( CacheContext context, String filename ) throws IOException
+ {
+ return buildCacheDir( context ).resolve( filename );
+ }
+
+ private Path localBuildPath( CacheContext context, String filename, boolean createDir ) throws IOException
+ {
+ final Path localBuildDir = localBuildDir( context );
+ if ( createDir )
+ {
+ Files.createDirectories( localBuildDir );
+ }
+ return localBuildDir.resolve( filename );
+ }
+
+ private Path localBuildDir( CacheContext context ) throws IOException
+ {
+ return buildCacheDir( context ).resolve( "local" );
+ }
+
+ private void logDebug( CacheContext context, String message )
+ {
+ logger.debug( "[CACHE][" + context.getProject().getArtifactId() + "] " + message );
+ }
+
+ private void logInfo( CacheContext context, String message )
+ {
+ logger.info( "[CACHE][" + context.getProject().getArtifactId() + "] " + message );
+ }
+
+ private static class LastModifiedComparator implements Comparator
+ {
+ @Override
+ public int compare( Path p1, Path p2 )
+ {
+ try
+ {
+ return Files.getLastModifiedTime( p1 ).compareTo( Files.getLastModifiedTime( p2 ) );
+ }
+ catch ( IOException e )
+ {
+ return 0;
+ }
+ }
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/MojoExecutionManager.java b/maven-core/src/main/java/org/apache/maven/caching/MojoExecutionManager.java
new file mode 100644
index 000000000000..9c07e5815e69
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/MojoExecutionManager.java
@@ -0,0 +1,178 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.commons.lang3.StringUtils;
+import org.apache.maven.caching.jaxb.CompletedExecutionType;
+import org.apache.maven.caching.jaxb.TrackedPropertyType;
+import org.apache.maven.caching.xml.BuildInfo;
+import org.apache.maven.caching.xml.CacheConfig;
+import org.apache.maven.caching.xml.DtoUtils;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.Mojo;
+import org.apache.maven.plugin.MojoCheker;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.logging.Logger;
+import org.codehaus.plexus.util.ReflectionUtils;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.apache.maven.caching.ProjectUtils.mojoExecutionKey;
+
+/**
+ * MojoExecutionManager
+ */
+public class MojoExecutionManager implements MojoCheker
+{
+
+ private final long createdTimestamp;
+ private final Logger logger;
+ private final MavenProject project;
+ private final BuildInfo buildInfo;
+ private final AtomicBoolean consistent;
+ private final CacheController cacheController;
+ private final CacheConfig cacheConfig;
+
+ public MojoExecutionManager( MavenProject project,
+ CacheController cacheController,
+ BuildInfo buildInfo,
+ AtomicBoolean consistent,
+ Logger logger, CacheConfig cacheConfig )
+ {
+ this.createdTimestamp = System.currentTimeMillis();
+ this.project = project;
+ this.cacheController = cacheController;
+ this.buildInfo = buildInfo;
+ this.consistent = consistent;
+ this.logger = logger;
+ this.cacheConfig = cacheConfig;
+ }
+
+ /**
+ * runtime check is rather expensive for cached build and better to be avoided when possible
+ */
+ @Override
+ public boolean needCheck( MojoExecution mojoExecution, MavenSession session )
+ {
+ return !cacheConfig.getTrackedProperties( mojoExecution ).isEmpty();
+ }
+
+ /**
+ * this implementation has side effect of consistency check to force local save if local run is different than
+ * cached
+ *
+ * @return false always returns false to prevent mojo execution
+ */
+ @Override
+ public boolean check( MojoExecution execution, Mojo mojo, MavenSession session )
+ {
+
+ final CompletedExecutionType completedExecution = buildInfo.findMojoExecutionInfo( execution );
+ final String fullGoalName = execution.getMojoDescriptor().getFullGoalName();
+
+ if ( completedExecution != null && !isParamsMatched( project, execution, mojo, completedExecution ) )
+ {
+ logInfo( project,
+ "Mojo cached parameters mismatch with actual, forcing full project build. Mojo: " + fullGoalName );
+ consistent.set( false );
+ }
+
+ if ( consistent.get() )
+ {
+ long elapsed = System.currentTimeMillis() - createdTimestamp;
+ logInfo( project, "Skipping plugin execution (reconciled in " + elapsed + " millis): " + fullGoalName );
+ }
+
+ if ( logger.isDebugEnabled() )
+ {
+ logger.debug(
+ "[CACHE][" + project.getArtifactId() + "] Checked " + fullGoalName + ", resolved mojo: " + mojo
+ + ", cached params:" + completedExecution );
+ }
+ return false;
+ }
+
+ private boolean isParamsMatched( MavenProject project,
+ MojoExecution mojoExecution,
+ Mojo mojo,
+ CompletedExecutionType completedExecution )
+ {
+
+ List tracked = cacheConfig.getTrackedProperties( mojoExecution );
+
+ for ( TrackedPropertyType trackedProperty : tracked )
+ {
+ final String propertyName = trackedProperty.getPropertyName();
+
+ String expectedValue = DtoUtils.findPropertyValue( propertyName, completedExecution );
+ if ( expectedValue == null && trackedProperty.isSetDefaultValue() )
+ {
+ expectedValue = trackedProperty.getDefaultValue();
+ }
+
+ final String currentValue;
+ try
+ {
+ currentValue = String.valueOf( ReflectionUtils.getValueIncludingSuperclasses( propertyName, mojo ) );
+ }
+ catch ( IllegalAccessException e )
+ {
+ logError( project, "Cannot extract plugin property " + propertyName + " from mojo " + mojo, e );
+ return false;
+ }
+
+ if ( !StringUtils.equals( currentValue, expectedValue ) )
+ {
+ if ( !StringUtils.equals( currentValue, trackedProperty.getSkipValue() ) )
+ {
+ logInfo( project,
+ "Plugin parameter mismatch found. Parameter: " + propertyName + ", expected: "
+ + expectedValue + ", actual: " + currentValue );
+ return false;
+ }
+ else
+ {
+ logWarn( project,
+ "Cache contains plugin execution with skip flag and might be incomplete. Property: "
+ + propertyName + ", execution: " + mojoExecutionKey( mojoExecution ) );
+ }
+ }
+ }
+ return true;
+ }
+
+ private void logInfo( MavenProject project, String message )
+ {
+ logger.info( "[CACHE][" + project.getArtifactId() + "] " + message );
+ }
+
+ private void logError( MavenProject project, String message, Exception e )
+ {
+ logger.error( "[CACHE][" + project.getArtifactId() + "] " + message, e );
+ }
+
+ private void logWarn( MavenProject project, String message )
+ {
+ logger.warn( "[CACHE][" + project.getArtifactId() + "] " + message );
+ }
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/MojoParametersListener.java b/maven-core/src/main/java/org/apache/maven/caching/MojoParametersListener.java
new file mode 100644
index 000000000000..8750a8dcca67
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/MojoParametersListener.java
@@ -0,0 +1,102 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.execution.MojoExecutionEvent;
+import org.apache.maven.execution.MojoExecutionListener;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * MojoParametersListener
+ */
+@Component( role = MojoExecutionListener.class,
+ hint = "MojoParametersListener" )
+public class MojoParametersListener implements MojoExecutionListener
+{
+
+ private final ConcurrentMap> projectExecutions =
+ new ConcurrentHashMap<>();
+
+ @Requirement
+ private Logger logger;
+
+ @Override
+ public void beforeMojoExecution( MojoExecutionEvent event )
+ {
+ final String executionKey = ProjectUtils.mojoExecutionKey( event.getExecution() );
+ logDebug( event.getProject(),
+ "Starting mojo execution: " + executionKey + ", class: " + event.getMojo().getClass() );
+ final MavenProject project = event.getProject();
+ Map projectEvents = projectExecutions.get( project );
+ if ( projectEvents == null )
+ {
+ Map candidate = new ConcurrentHashMap<>();
+ projectEvents = projectExecutions.putIfAbsent( project, candidate );
+ if ( projectEvents == null )
+ {
+ projectEvents = candidate;
+ }
+ }
+ projectEvents.put( executionKey, event );
+ }
+
+ @Override
+ public void afterMojoExecutionSuccess( MojoExecutionEvent event ) throws MojoExecutionException
+ {
+ // do nothing
+ }
+
+ @Override
+ public void afterExecutionFailure( MojoExecutionEvent event )
+ {
+ //do nothing
+ }
+
+ public Map getProjectExecutions( MavenProject project )
+ {
+ return projectExecutions.get( project );
+ }
+
+ public void remove( MavenProject project )
+ {
+ projectExecutions.remove( project );
+ }
+
+ private void logDebug( MavenProject project, String message )
+ {
+ if ( logger.isDebugEnabled() )
+ {
+ logger.debug( "[CACHE][" + project.getArtifactId() + "] " + message );
+ }
+ }
+
+ // private void logInfo(String message) {
+ // logger.info("[CACHE][" + project.getArtifactId() + "] " + message);
+ // }
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/PluginScanConfig.java b/maven-core/src/main/java/org/apache/maven/caching/PluginScanConfig.java
new file mode 100644
index 000000000000..93bcccba0b1c
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/PluginScanConfig.java
@@ -0,0 +1,41 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.caching.jaxb.DirScanConfigType;
+
+import javax.annotation.Nonnull;
+
+/**
+ * PluginScanConfig
+ */
+public interface PluginScanConfig
+{
+ boolean isSkip();
+
+ boolean accept( String propertyName );
+
+ PluginScanConfig mergeWith( PluginScanConfig overrideSource );
+
+ @Nonnull
+ ScanConfigProperties getTagScanProperties( String tagName );
+
+ DirScanConfigType dto();
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/PluginScanConfigImpl.java b/maven-core/src/main/java/org/apache/maven/caching/PluginScanConfigImpl.java
new file mode 100644
index 000000000000..87791905100d
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/PluginScanConfigImpl.java
@@ -0,0 +1,161 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.commons.lang3.StringUtils;
+import org.apache.maven.caching.jaxb.DirScanConfigType;
+import org.apache.maven.caching.jaxb.TagNameType;
+import org.apache.maven.caching.jaxb.TagScanConfigType;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+
+/**
+ * PluginScanConfigImpl
+ */
+public class PluginScanConfigImpl implements PluginScanConfig
+{
+
+ private final DirScanConfigType dto;
+
+ public PluginScanConfigImpl( DirScanConfigType scanConfig )
+ {
+ this.dto = scanConfig;
+ }
+
+ @Override
+ public boolean isSkip()
+ {
+ return StringUtils.equals( dto.getMode(), "skip" );
+ }
+
+ @Override
+ public boolean accept( String tagName )
+ {
+ // include or exclude is a choice element, could be only obe property set
+
+ //noinspection ConstantConditions
+ final List includes = dto.getInclude();
+ if ( !includes.isEmpty() )
+ {
+ return findTagScanProperties( tagName ) != null;
+ }
+
+ return !contains( dto.getExclude(), tagName );
+ }
+
+ private boolean contains( List excludes, String tagName )
+ {
+ for ( TagNameType exclude : excludes )
+ {
+ if ( StringUtils.equals( exclude.getTagName(), tagName ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Nonnull
+ @Override
+ public PluginScanConfig mergeWith( final PluginScanConfig overrideConfig )
+ {
+
+ if ( dto == null )
+ {
+ return overrideConfig;
+ }
+
+ final DirScanConfigType override = overrideConfig.dto();
+ if ( override == null )
+ {
+ return this;
+ }
+
+ if ( override.isIgnoreParent() )
+ {
+ return overrideConfig;
+ }
+
+ DirScanConfigType merged = new DirScanConfigType();
+ if ( override.isSetMode() )
+ {
+ merged.setMode( override.getMode() );
+ }
+ else
+ {
+ merged.setMode( dto.getMode() );
+ }
+
+ merged.getExclude().addAll( dto.getExclude() );
+ merged.getExclude().addAll( override.getExclude() );
+
+ merged.getInclude().addAll( dto.getInclude() );
+ merged.getInclude().addAll( override.getInclude() );
+
+ return new PluginScanConfigImpl( merged );
+ }
+
+ @Nonnull
+ public ScanConfigProperties getTagScanProperties( String tagName )
+ {
+ ScanConfigProperties scanProperties = findTagScanProperties( tagName );
+ return scanProperties != null ? scanProperties : defaultScanConfig();
+ }
+
+ @Override
+ public DirScanConfigType dto()
+ {
+ return dto;
+ }
+
+ private ScanConfigProperties findTagScanProperties( String tagName )
+ {
+ ScanConfigProperties scanConfigProperties = findConfigByName( tagName, dto.getInclude() );
+ if ( scanConfigProperties == null )
+ {
+ scanConfigProperties = findConfigByName( tagName, dto.getTagScanConfig() );
+ }
+ return scanConfigProperties;
+ }
+
+ private ScanConfigProperties findConfigByName( String tagName, List configs )
+ {
+
+ if ( configs == null )
+ {
+ return null;
+ }
+
+ for ( TagScanConfigType config : configs )
+ {
+ if ( StringUtils.equals( tagName, config.getTagName() ) )
+ {
+ return new ScanConfigProperties( config.isRecursive(), config.getGlob() );
+ }
+ }
+ return null;
+ }
+
+ private static ScanConfigProperties defaultScanConfig()
+ {
+ return new ScanConfigProperties( true, null );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/ProjectUtils.java b/maven-core/src/main/java/org/apache/maven/caching/ProjectUtils.java
new file mode 100644
index 000000000000..176556850377
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/ProjectUtils.java
@@ -0,0 +1,197 @@
+package org.apache.maven.caching;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.caching.jaxb.BuildInfoType;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.internal.ProjectIndex;
+import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.project.MavenProject;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.apache.commons.lang3.StringUtils.removeStart;
+import static org.apache.commons.lang3.StringUtils.trim;
+import static org.apache.maven.artifact.Artifact.LATEST_VERSION;
+import static org.apache.maven.artifact.Artifact.SNAPSHOT_VERSION;
+
+/**
+ * ProjectUtils
+ */
+public class ProjectUtils
+{
+
+ private static final List PHASES = Lists.newArrayList(
+ //clean
+ "pre-clean", "clean", "post-clean",
+ // default
+ "validate", "initialize", "generate-sources", "process-sources", "generate-resources", "process-resources",
+ "compile", "process-classes", "generate-test-sources", "process-test-sources", "generate-test-resources",
+ "process-test-resources", "test-compile", "process-test-classes", "test", "prepare-package", "package",
+ "pre-integration-test", "integration-test", "post-integration-test", "verify", "install", "deploy",
+ //site
+ "pre-site", "site", "post-site", "site-deploy" );
+
+ /**
+ * @param phase
+ * @param other
+ * @return true if the given phase is later than the other in maven lifecycle. Example: isLaterPhase("install",
+ * "clean") returns true;
+ */
+ public static boolean isLaterPhase( String phase, String other )
+ {
+ checkArgument( PHASES.contains( phase ), "Unsupported phase: " + phase );
+ checkArgument( PHASES.contains( other ), "Unsupported phase: " + other );
+
+ return PHASES.indexOf( phase ) > PHASES.indexOf( other );
+ }
+
+ public static boolean isBuilding( Dependency dependency, ProjectIndex projectIndex )
+ {
+ final MavenProject key = new MavenProject();
+ key.setGroupId( dependency.getGroupId() );
+ key.setArtifactId( dependency.getArtifactId() );
+ key.setVersion( dependency.getVersion() );
+ return projectIndex.getProjects().containsKey( BuilderCommon.getKey( key ) );
+ }
+
+ public static boolean isPomPackaging( MavenProject project )
+ {
+ return project.getPackaging().equals( "pom" ) && !new File( getSrcDir( project ) ).exists();
+ }
+
+ public static boolean isPom( Artifact artifact )
+ {
+ return artifact.getType().equals( "pom" );
+ }
+
+ public static boolean isPom( Dependency dependency )
+ {
+ return dependency.getType().equals( "pom" );
+ }
+
+ public static boolean isSnapshot( String version )
+ {
+ return version.endsWith( SNAPSHOT_VERSION ) || version.endsWith( LATEST_VERSION );
+ }
+
+ public static String getTargetDir( MavenProject project )
+ {
+ return FilenameUtils.concat( project.getBasedir().getAbsolutePath(), "target" );
+ }
+
+ public static String getSrcDir( MavenProject project )
+ {
+ return FilenameUtils.concat( project.getBasedir().getAbsolutePath(), "src" );
+ }
+
+ public static String normalizedName( Artifact artifact )
+ {
+
+ if ( artifact.getFile() == null )
+ {
+ return null;
+ }
+
+ StringBuilder filename = new StringBuilder( artifact.getArtifactId() );
+
+ if ( artifact.hasClassifier() )
+ {
+ filename.append( "-" ).append( artifact.getClassifier() );
+ }
+
+ final ArtifactHandler artifactHandler = artifact.getArtifactHandler();
+ if ( artifactHandler != null && StringUtils.isNotBlank( artifactHandler.getExtension() ) )
+ {
+ filename.append( "." ).append( artifactHandler.getExtension() );
+ }
+ return filename.toString();
+ }
+
+ public static String mojoExecutionKey( MojoExecution mojo )
+ {
+ return StringUtils.join( Lists.newArrayList( StringUtils.defaultIfEmpty( mojo.getExecutionId(), "emptyExecId" ),
+ StringUtils.defaultIfEmpty( mojo.getGoal(), "emptyGoal" ),
+ StringUtils.defaultIfEmpty( mojo.getLifecyclePhase(), "emptyLifecyclePhase" ),
+ StringUtils.defaultIfEmpty( mojo.getArtifactId(), "emptyArtifactId" ),
+ StringUtils.defaultIfEmpty( mojo.getGroupId(), "emptyGroupId" ),
+ StringUtils.defaultIfEmpty( mojo.getVersion(), "emptyVersion" ) ), ":" );
+ }
+
+ public static String getMultimoduleRoot( MavenSession session )
+ {
+ return System.getProperty( "maven.multiModuleProjectDirectory", session.getExecutionRootDirectory() );
+ }
+
+ public static BuildInfoType.Scm readGitInfo( MavenSession session ) throws IOException
+ {
+ final BuildInfoType.Scm scmCandidate = new BuildInfoType.Scm();
+ final Path gitDir = Paths.get( getMultimoduleRoot( session ), ".git" );
+ if ( Files.isDirectory( gitDir ) )
+ {
+ final Path headFile = gitDir.resolve( "HEAD" );
+ if ( Files.exists( headFile ) )
+ {
+ String headRef = readFirstLine( headFile, "" );
+ if ( headRef.startsWith( "ref: " ) )
+ {
+ String branch = trim( removeStart( headRef, "ref: " ) );
+ scmCandidate.setSourceBranch( branch );
+ final Path refPath = gitDir.resolve( branch );
+ if ( Files.exists( refPath ) )
+ {
+ String revision = readFirstLine( refPath, "" );
+ scmCandidate.setRevision( trim( revision ) );
+ }
+ }
+ else
+ {
+ scmCandidate.setSourceBranch( headRef );
+ scmCandidate.setRevision( headRef );
+ }
+ }
+ }
+ return scmCandidate;
+ }
+
+
+ private static String readFirstLine( Path path, String defaultValue ) throws IOException
+ {
+ final List lines = Files.readAllLines( path, StandardCharsets.UTF_8 );
+ return Iterables.getFirst( lines, defaultValue );
+ }
+
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/RemoteArtifactsRepository.java b/maven-core/src/main/java/org/apache/maven/caching/RemoteArtifactsRepository.java
new file mode 100644
index 000000000000..7c118c405739
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/RemoteArtifactsRepository.java
@@ -0,0 +1,42 @@
+package org.apache.maven.caching;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.base.Optional;
+import org.apache.maven.caching.jaxb.ArtifactType;
+import org.apache.maven.caching.xml.BuildInfo;
+import org.apache.maven.project.MavenProject;
+
+import java.io.IOException;
+
+/**
+ * RemoteArtifactsRepository
+ */
+public interface RemoteArtifactsRepository extends ArtifactsRepository
+{
+
+ byte[] getArtifactContent( CacheContext context, ArtifactType artifact ) throws IOException;
+
+ byte[] getResourceContent( String resourceUrl, String logReference );
+
+ String getResourceUrl( CacheContext context, String filename );
+
+ Optional findBaselineBuild( MavenProject project );
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/RestoreStatus.java b/maven-core/src/main/java/org/apache/maven/caching/RestoreStatus.java
new file mode 100644
index 000000000000..6bf8fefc2832
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/RestoreStatus.java
@@ -0,0 +1,31 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.
+ */
+
+/**
+ * RestoreStatus
+ */
+public enum RestoreStatus
+{
+ EMPTY,
+ FAILURE,
+ PARTIAL,
+ SUCCESS
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/ScanConfigProperties.java b/maven-core/src/main/java/org/apache/maven/caching/ScanConfigProperties.java
new file mode 100644
index 000000000000..bc9622a59fa8
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/ScanConfigProperties.java
@@ -0,0 +1,45 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.
+ */
+
+/**
+ * ScanConfigProperties
+ */
+public class ScanConfigProperties
+{
+ private final boolean recursive;
+ private final String glob;
+
+ public ScanConfigProperties( boolean recursive, String glob )
+ {
+ this.recursive = recursive;
+ this.glob = glob;
+ }
+
+ public boolean isRecursive()
+ {
+ return recursive;
+ }
+
+ public String getGlob()
+ {
+ return glob;
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/ZipUtils.java b/maven-core/src/main/java/org/apache/maven/caching/ZipUtils.java
new file mode 100644
index 000000000000..9f15bb1d2460
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/ZipUtils.java
@@ -0,0 +1,116 @@
+package org.apache.maven.caching;
+
+/*
+ * 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.commons.io.IOUtils;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * ZipUtils
+ */
+public class ZipUtils
+{
+
+ private static final int BUFFER_SIZE = 4096;
+
+ public static InputStream zipFolder( final Path dir ) throws IOException
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try ( ZipOutputStream zipOutputStream = new ZipOutputStream( out ) )
+ {
+ processFolder( dir, zipOutputStream );
+ }
+ return new ByteArrayInputStream( out.toByteArray() );
+ }
+
+ private static void processFolder( final Path dir, final ZipOutputStream zipOutputStream ) throws IOException
+ {
+ Files.walkFileTree( dir, new SimpleFileVisitor()
+ {
+ @Override
+ public FileVisitResult visitFile( Path path, BasicFileAttributes basicFileAttributes ) throws IOException
+ {
+ final ZipEntry zipEntry = new ZipEntry( dir.relativize( path ).toString() );
+ zipOutputStream.putNextEntry( zipEntry );
+ try ( InputStream inputStream = Files.newInputStream( path ) )
+ {
+ IOUtils.copy( inputStream, zipOutputStream );
+ }
+ zipOutputStream.closeEntry();
+ return FileVisitResult.CONTINUE;
+ }
+ } );
+ }
+
+ public static void unzip( InputStream is, Path out ) throws IOException
+ {
+ try ( ZipInputStream zis = new ZipInputStream( is ) )
+ {
+
+ ZipEntry entry = zis.getNextEntry();
+
+ while ( entry != null )
+ {
+ File file = new File( out.toFile(), entry.getName() );
+ file.setLastModified( entry.getTime() );
+
+ if ( entry.isDirectory() )
+ {
+ file.mkdirs();
+ }
+ else
+ {
+ File parent = file.getParentFile();
+
+ if ( !parent.exists() )
+ {
+ parent.mkdirs();
+ }
+
+ try ( BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream( file ) ) )
+ {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int location;
+ while ( ( location = zis.read( buffer ) ) != -1 )
+ {
+ bos.write( buffer, 0, location );
+ }
+ }
+ }
+ entry = zis.getNextEntry();
+ }
+ }
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/checksum/DependencyNotResolvedException.java b/maven-core/src/main/java/org/apache/maven/caching/checksum/DependencyNotResolvedException.java
new file mode 100644
index 000000000000..bcc017b8caab
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/checksum/DependencyNotResolvedException.java
@@ -0,0 +1,31 @@
+package org.apache.maven.caching.checksum;
+
+/*
+ * 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.
+ */
+
+/**
+ * DependencyNotResolvedException
+ */
+public class DependencyNotResolvedException extends RuntimeException
+{
+ public DependencyNotResolvedException( String message )
+ {
+ super( message );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/checksum/DigestUtils.java b/maven-core/src/main/java/org/apache/maven/caching/checksum/DigestUtils.java
new file mode 100644
index 000000000000..e837da1f8587
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/checksum/DigestUtils.java
@@ -0,0 +1,189 @@
+package org.apache.maven.caching.checksum;
+
+/*
+ * 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.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.caching.hash.HashChecksum;
+import org.apache.maven.caching.jaxb.DigestItemType;
+import org.mozilla.universalchardet.UniversalDetector;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.commons.lang3.StringUtils.containsAny;
+import static org.apache.commons.lang3.StringUtils.equalsAny;
+import static org.apache.commons.lang3.StringUtils.startsWith;
+import static org.apache.commons.lang3.StringUtils.startsWithAny;
+
+/**
+ * DigestUtils
+ */
+public class DigestUtils
+{
+
+ private static final ThreadLocal ENCODING_DETECTOR = new ThreadLocal()
+ {
+ @Override
+ protected UniversalDetector initialValue()
+ {
+ return new UniversalDetector( null );
+ }
+ };
+
+
+ public static DigestItemType pom( HashChecksum checksum, String effectivePom )
+ {
+ return item( "pom", effectivePom, checksum.update( effectivePom.getBytes( UTF_8 ) ) );
+ }
+
+ public static DigestItemType file( HashChecksum checksum, Path basedir, Path file ) throws IOException
+ {
+ byte[] content = Files.readAllBytes( file );
+ DigestItemType item = item( "file", normalize( basedir, file ), checksum.update( content ) );
+ try
+ {
+ populateContentDetails( file, content, item );
+ }
+ catch ( IOException ignore )
+ {
+ System.out.println( "hello" );
+ }
+ return item;
+ }
+
+ private static void populateContentDetails( Path file, byte[] content, DigestItemType item ) throws IOException
+ {
+ String contentType = Files.probeContentType( file );
+ if ( contentType != null )
+ {
+ item.setContent( contentType );
+ }
+ final boolean binary = isBinary( contentType );
+ item.setIsText( isText( contentType ) ? "yes" : binary ? "no" : "unknown" );
+ if ( !binary )
+ { // probing application/ files as well though might be binary
+ UniversalDetector detector = ENCODING_DETECTOR.get();
+ detector.reset();
+ detector.handleData( content, 0, Math.min( content.length, 16 * 1024 ) );
+ detector.dataEnd();
+ String detectedCharset = detector.getDetectedCharset();
+ Charset charset = UTF_8;
+ if ( detectedCharset != null )
+ {
+ item.setCharset( detectedCharset );
+ charset = Charset.forName( detectedCharset );
+ }
+ CharBuffer charBuffer = charset.decode( ByteBuffer.wrap( content ) );
+ String lineSeparator = detectLineSeparator( charBuffer );
+ item.setEol( StringUtils.defaultString( lineSeparator, "unknown" ) );
+ }
+ }
+
+ // TODO add support for .gitattributes to statically configure file type before falling back to probe based content checks
+ private static boolean isText( String contentType )
+ {
+ return startsWith( contentType, "text/" )
+ || containsAny( contentType, "+json", "+xml" ) // common mime type suffixes
+ || equalsAny( contentType, // some common text types
+ "application/json",
+ "application/rtf",
+ "application/x-sh",
+ "application/xml",
+ "application/javascript",
+ "application/sql"
+ );
+ }
+
+ private static boolean isBinary( String contentType )
+ {
+ return startsWithAny( contentType, "image/", "audio/", "video/", "font/" )
+ || containsAny( contentType, "+zip", "+gzip" )
+ || equalsAny( contentType,
+ "application/octet-stream",
+ "application/java-archive",
+ "application/x-bzip",
+ "application/x-bzip2",
+ "application/zip",
+ "application/gzip",
+ "application/x-tar",
+ "application/msword",
+ "application/vnd.ms-excel",
+ "application/vnd.ms-powerpoint",
+ "application/pdf"
+ );
+ }
+
+ public static DigestItemType dependency( HashChecksum checksum, String key, String hash )
+ {
+ return item( "dependency", key, checksum.update( hash ) );
+ }
+
+ private static String normalize( Path basedirPath, Path file )
+ {
+ return FilenameUtils.separatorsToUnix( relativize( basedirPath, file ).toString() );
+ }
+
+ private static Path relativize( Path basedirPath, Path file )
+ {
+ try
+ {
+ return basedirPath.relativize( file );
+ }
+ catch ( Exception ignore )
+ {
+ return file;
+ }
+ }
+
+ private static DigestItemType item( String type, String reference, String hash )
+ {
+ final DigestItemType item = new DigestItemType();
+ item.setType( type );
+ item.setValue( reference );
+ item.setHash( hash );
+ return item;
+ }
+
+ private DigestUtils()
+ {
+ }
+
+ public static String detectLineSeparator( CharSequence text )
+ {
+ // first line break only
+ int index = StringUtils.indexOfAny( text, "\n\r" );
+ if ( index == -1 || index >= text.length() )
+ {
+ return null;
+ }
+ char ch = text.charAt( index );
+ if ( ch == '\r' )
+ {
+ return index + 1 < text.length() && text.charAt( index + 1 ) == '\n' ? "CRLF" : "CR";
+ }
+ return ch == '\n' ? "LF" : null;
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/checksum/KeyUtils.java b/maven-core/src/main/java/org/apache/maven/caching/checksum/KeyUtils.java
new file mode 100644
index 000000000000..04d9207cb0dc
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/checksum/KeyUtils.java
@@ -0,0 +1,64 @@
+package org.apache.maven.caching.checksum;
+
+/*
+ * 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.commons.lang3.StringUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.caching.jaxb.ArtifactType;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+
+/**
+ * KeyUtils
+ */
+public class KeyUtils
+{
+
+ private static final String SEPARATOR = ":";
+
+ public static String getProjectKey( MavenProject project )
+ {
+ return StringUtils.joinWith( SEPARATOR, project.getGroupId(), project.getArtifactId(), project.getVersion() );
+ }
+
+ public static String getVersionlessProjectKey( MavenProject project )
+ {
+ return StringUtils.joinWith( SEPARATOR, project.getGroupId(), project.getArtifactId() );
+ }
+
+ public static String getVersionlessDependencyKey( Dependency dependency )
+ {
+ return StringUtils.joinWith( SEPARATOR, dependency.getGroupId(), dependency.getArtifactId() );
+ }
+
+ public static String getArtifactKey( ArtifactType artifact )
+ {
+ return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getType()
+ + ( artifact.getClassifier() != null ? ":" + artifact.getClassifier() : "" )
+ + ":" + artifact.getVersion();
+ }
+
+ public static String getArtifactKey( Artifact artifact )
+ {
+ return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getType()
+ + ( artifact.getClassifier() != null ? ":" + artifact.getClassifier() : "" )
+ + ":" + artifact.getVersion();
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/checksum/MavenProjectInput.java b/maven-core/src/main/java/org/apache/maven/caching/checksum/MavenProjectInput.java
new file mode 100644
index 000000000000..8e5873ce7dcd
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/checksum/MavenProjectInput.java
@@ -0,0 +1,950 @@
+package org.apache.maven.caching.checksum;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.caching.Clock;
+import org.apache.maven.caching.LocalArtifactsRepository;
+import org.apache.maven.caching.PluginScanConfig;
+import org.apache.maven.caching.ProjectUtils;
+import org.apache.maven.caching.RemoteArtifactsRepository;
+import org.apache.maven.caching.ScanConfigProperties;
+import org.apache.maven.caching.hash.HashAlgorithm;
+import org.apache.maven.caching.hash.HashChecksum;
+import org.apache.maven.caching.hash.HashFactory;
+import org.apache.maven.caching.jaxb.DigestItemType;
+import org.apache.maven.caching.jaxb.ProjectsInputInfoType;
+import org.apache.maven.caching.xml.BuildInfo;
+import org.apache.maven.caching.xml.CacheConfig;
+import org.apache.maven.caching.xml.DtoUtils;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.internal.ProjectIndex;
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginExecution;
+import org.apache.maven.model.PluginManagement;
+import org.apache.maven.model.Resource;
+import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.repository.RepositorySystem;
+import org.codehaus.plexus.logging.Logger;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.WriterFactory;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+import javax.annotation.Nonnull;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.apache.commons.lang3.StringUtils.contains;
+import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
+import static org.apache.commons.lang3.StringUtils.equalsAnyIgnoreCase;
+import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.apache.commons.lang3.StringUtils.replaceEachRepeatedly;
+import static org.apache.commons.lang3.StringUtils.startsWithAny;
+import static org.apache.commons.lang3.StringUtils.stripToEmpty;
+import static org.apache.maven.caching.ProjectUtils.isBuilding;
+import static org.apache.maven.caching.ProjectUtils.isSnapshot;
+import static org.apache.maven.caching.jaxb.PathSetType.Include;
+
+/**
+ * MavenProjectInput
+ */
+public class MavenProjectInput
+{
+
+ /**
+ * Version ov hashing algorithm implementation. It is recommended to change to simplify remote cache maintenance
+ */
+ public static final String CACHE_IMPLMENTATION_VERSION = "v10";
+
+ /**
+ * property name to pass glob value. The glob to be used to list directory files in plugins scanning
+ */
+ private static final String CACHE_INPUT_GLOB_NAME = "remote.cache.input.glob";
+ /**
+ * default glob, bbsdk/abfx specific
+ */
+ public static final String DEFAULT_GLOB = "{*.java,*.groovy,*.yaml,*.svcd,*.proto,*assembly.xml,assembly"
+ + "*.xml,*logback.xml,*.vm,*.ini,*.jks,*.properties,*.sh,*.bat}";
+ /**
+ * property name prefix to pass input files with project properties. smth like remote.cache.input.1 will be
+ * accepted
+ */
+ private static final String CACHE_INPUT_NAME = "remote.cache.input";
+ /**
+ * property name prefix to exclude files from input. smth like remote.cache.exclude.1 should be set in project
+ * props
+ */
+ private static final String CACHE_EXCLUDE_NAME = "remote.cache.exclude";
+ /**
+ * Flag to control if we should check values from plugin configs as file system objects
+ */
+ private static final String CACHE_PROCESS_PLUGINS = "remote.cache.processPlugins";
+ private final Logger logger;
+ private final MavenProject project;
+ private final MavenSession session;
+ private final LocalArtifactsRepository localCache;
+ private final RemoteArtifactsRepository remoteCache;
+ private final RepositorySystem repoSystem;
+ private final ArtifactHandlerManager artifactHandlerManager;
+ private final CacheConfig config;
+ private final ConcurrentMap projectArtifactsByKey;
+ private final PathIgnoringCaseComparator fileComparator;
+ private final DependencyComparator dependencyComparator;
+ private final List filteredOutPaths;
+ private final Path baseDirPath;
+ private final String dirGlob;
+ private final boolean processPlugins;
+ private final ProjectIndex projectIndex;
+
+ @SuppressWarnings( "checkstyle:parameternumber" )
+ public MavenProjectInput( MavenProject project,
+ MavenSession session,
+ CacheConfig config,
+ ProjectIndex projectIndex,
+ ConcurrentMap artifactsByKey,
+ RepositorySystem repoSystem,
+ ArtifactHandlerManager artifactHandlerManager,
+ Logger logger,
+ LocalArtifactsRepository localCache,
+ RemoteArtifactsRepository remoteCache )
+ {
+ this.project = project;
+ this.session = session;
+ this.config = config;
+ this.projectIndex = projectIndex;
+ this.projectArtifactsByKey = artifactsByKey;
+ this.baseDirPath = project.getBasedir().toPath().toAbsolutePath();
+ this.repoSystem = repoSystem;
+ this.artifactHandlerManager = artifactHandlerManager;
+ this.logger = logger;
+ this.localCache = localCache;
+ this.remoteCache = remoteCache;
+ Properties properties = project.getProperties();
+ this.dirGlob = properties.getProperty( CACHE_INPUT_GLOB_NAME, config.getDefaultGlob() );
+ this.processPlugins = Boolean.parseBoolean(
+ properties.getProperty( CACHE_PROCESS_PLUGINS, config.isProcessPlugins() ) );
+
+ Build build = project.getBuild();
+ filteredOutPaths = new ArrayList<>( Arrays.asList( normalizedPath( build.getDirectory() ), // target by default
+ normalizedPath( build.getOutputDirectory() ), normalizedPath( build.getTestOutputDirectory() ) ) );
+
+ for ( String excludePath : config.getGlobalExcludePaths() )
+ {
+ filteredOutPaths.add( Paths.get( excludePath ) );
+ }
+
+ for ( String propertyName : properties.stringPropertyNames() )
+ {
+ if ( propertyName.startsWith( CACHE_EXCLUDE_NAME ) )
+ {
+ filteredOutPaths.add( Paths.get( properties.getProperty( propertyName ) ) );
+ }
+ }
+
+ this.fileComparator = new PathIgnoringCaseComparator();
+ this.dependencyComparator = new DependencyComparator();
+ }
+
+ public ProjectsInputInfoType calculateChecksum( HashFactory hashFactory ) throws IOException
+ {
+ long time = Clock.time();
+
+ final String effectivePom = getEffectivePom( project.getOriginalEffectiveModel() );
+ final SortedSet inputFiles = getInputFiles();
+ final SortedMap dependenciesChecksum = getMutableDependencies();
+
+ final long inputTime = Clock.elapsed( time );
+ time = Clock.time();
+
+ // hash items: effective pom + input files + dependencies
+ final int count = 1 + inputFiles.size() + dependenciesChecksum.size();
+ final List items = new ArrayList<>( count );
+ final HashChecksum checksum = hashFactory.createChecksum( count );
+
+ Optional baselineHolder = Optional.absent();
+ if ( config.isBaselineDiffEnabled() )
+ {
+ baselineHolder =
+ remoteCache.findBaselineBuild( project ).transform( b -> b.getDto().getProjectsInputInfo() );
+ }
+
+ DigestItemType effectivePomChecksum = DigestUtils.pom( checksum, effectivePom );
+ items.add( effectivePomChecksum );
+ final boolean compareWithBaseline = config.isBaselineDiffEnabled() && baselineHolder.isPresent();
+ if ( compareWithBaseline )
+ {
+ checkEffectivePomMatch( baselineHolder.get(), effectivePomChecksum );
+ }
+
+ boolean sourcesMatched = true;
+ for ( Path file : inputFiles )
+ {
+ DigestItemType fileDigest = DigestUtils.file( checksum, baseDirPath, file );
+ items.add( fileDigest );
+ if ( compareWithBaseline )
+ {
+ sourcesMatched &= checkItemMatchesBaseline( baselineHolder.get(), fileDigest );
+ }
+ }
+ if ( compareWithBaseline )
+ {
+ logInfo( "Source code: " + ( sourcesMatched ? "MATCHED" : "OUT OF DATE" ) );
+ }
+
+ boolean dependenciesMatched = true;
+ for ( Map.Entry entry : dependenciesChecksum.entrySet() )
+ {
+ DigestItemType dependencyDigest =
+ DigestUtils.dependency( checksum, entry.getKey(), entry.getValue().getHash() );
+ items.add( dependencyDigest );
+ if ( compareWithBaseline )
+ {
+ dependenciesMatched &= checkItemMatchesBaseline( baselineHolder.get(), dependencyDigest );
+ }
+ }
+
+ if ( compareWithBaseline )
+ {
+ logInfo( "Dependencies: " + ( dependenciesMatched ? "MATCHED" : "OUT OF DATE" ) );
+ }
+
+ final ProjectsInputInfoType projectsInputInfoType = new ProjectsInputInfoType();
+ projectsInputInfoType.setChecksum( checksum.digest() );
+ projectsInputInfoType.getItem().addAll( items );
+
+ final long checksumTime = Clock.elapsed( time );
+
+ if ( logger.isDebugEnabled() )
+ {
+ for ( DigestItemType item : projectsInputInfoType.getItem() )
+ {
+ logger.debug( "Hash calculated, item: " + item.getType() + ", hash: " + item.getHash() );
+ }
+ }
+ logInfo(
+ "Project inputs calculated in " + inputTime + " ms. " + hashFactory.getAlgorithm()
+ + " checksum [" + projectsInputInfoType.getChecksum() + "] calculated in "
+ + checksumTime + " ms." );
+ return projectsInputInfoType;
+ }
+
+ private void checkEffectivePomMatch( ProjectsInputInfoType baselineBuild, DigestItemType effectivePomChecksum )
+ {
+ Optional pomHolder = Optional.absent();
+ for ( DigestItemType it : baselineBuild.getItem() )
+ {
+ if ( it.getType().equals( "pom" ) )
+ {
+ pomHolder = Optional.of( it );
+ break;
+ }
+ }
+
+ if ( pomHolder.isPresent() )
+ {
+ DigestItemType pomItem = pomHolder.get();
+ final boolean matches = StringUtils.equals( pomItem.getHash(), effectivePomChecksum.getHash() );
+ if ( !matches )
+ {
+ logInfo(
+ "Mismatch in effective poms. Current: " + effectivePomChecksum.getHash() + ", remote: "
+ + pomItem.getHash() );
+ }
+ logInfo( "Effective pom: " + ( matches ? "MATCHED" : "OUT OF DATE" ) );
+ }
+ }
+
+ private boolean checkItemMatchesBaseline( ProjectsInputInfoType baselineBuild, DigestItemType fileDigest )
+ {
+ Optional baselineFileDigest = Optional.absent();
+ for ( DigestItemType it : baselineBuild.getItem() )
+ {
+ if ( it.getType().equals( fileDigest.getType() )
+ && fileDigest.getValue().equals( it.getValue().trim() ) )
+ {
+ baselineFileDigest = Optional.of( it );
+ break;
+ }
+ }
+
+ boolean matched = false;
+ if ( baselineFileDigest.isPresent() )
+ {
+ String hash = baselineFileDigest.get().getHash();
+ matched = StringUtils.equals( hash, fileDigest.getHash() );
+ if ( !matched )
+ {
+ logInfo(
+ "Mismatch in " + fileDigest.getType() + ": " + fileDigest.getValue() + ". Local hash: "
+ + fileDigest.getHash() + ", remote: " + hash );
+ }
+ }
+ else
+ {
+ logInfo(
+ "Mismatch in " + fileDigest.getType() + ": " + fileDigest.getValue()
+ + ". Not found in remote cache" );
+ }
+ return matched;
+ }
+
+ /**
+ * @param prototype effective model fully resolved by maven build. Do not pass here just parsed Model.
+ */
+ private String getEffectivePom( Model prototype ) throws IOException
+ {
+ // TODO validate status of the model - it should be in resolved state
+ Model toHash = new Model();
+
+ toHash.setGroupId( prototype.getGroupId() );
+ toHash.setArtifactId( prototype.getArtifactId() );
+ toHash.setVersion( prototype.getVersion() );
+ toHash.setModules( prototype.getModules() );
+
+ Collections.sort( prototype.getDependencies(), dependencyComparator );
+ toHash.setDependencies( prototype.getDependencies() );
+
+ PluginManagement pluginManagement = prototype.getBuild().getPluginManagement();
+ pluginManagement.setPlugins( normalizePlugins( prototype.getBuild().getPluginManagement().getPlugins() ) );
+
+ List plugins = normalizePlugins( prototype.getBuild().getPlugins() );
+
+ Build build = new Build();
+ build.setPluginManagement( pluginManagement );
+ build.setPlugins( plugins );
+
+ toHash.setBuild( build );
+
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+
+ Writer writer = null;
+ try
+ {
+ writer = WriterFactory.newXmlWriter( output );
+ new MavenXpp3Writer().write( writer, toHash );
+
+ //normalize env specifics
+ final String[] searchList = {baseDirPath.toString(), "\\", "windows", "linux"};
+ final String[] replacementList = {"", "/", "os.classifier", "os.classifier"};
+
+ return replaceEachRepeatedly( output.toString(), searchList, replacementList );
+
+ }
+ finally
+ {
+ IOUtil.close( writer );
+ }
+ }
+
+ private SortedSet getInputFiles()
+ {
+ long start = System.currentTimeMillis();
+ HashSet visitedDirs = new HashSet<>();
+ ArrayList collectedFiles = new ArrayList<>();
+
+ Build build = project.getBuild();
+
+ final boolean recursive = true;
+ startWalk( Paths.get( build.getSourceDirectory() ), dirGlob, recursive, collectedFiles, visitedDirs );
+ for ( Resource resource : build.getResources() )
+ {
+ startWalk( Paths.get( resource.getDirectory() ), dirGlob, recursive, collectedFiles, visitedDirs );
+ }
+
+ startWalk( Paths.get( build.getTestSourceDirectory() ), dirGlob, recursive, collectedFiles, visitedDirs );
+ for ( Resource testResource : build.getTestResources() )
+ {
+ startWalk( Paths.get( testResource.getDirectory() ), dirGlob, recursive, collectedFiles, visitedDirs );
+ }
+
+ Properties properties = project.getProperties();
+ for ( String name : properties.stringPropertyNames() )
+ {
+ if ( name.startsWith( CACHE_INPUT_NAME ) )
+ {
+ String path = properties.getProperty( name );
+ startWalk( Paths.get( path ), dirGlob, recursive, collectedFiles, visitedDirs );
+ }
+ }
+
+ List includes = config.getGlobalIncludePaths();
+ for ( Include include : includes )
+ {
+ final String path = include.getValue();
+ final String glob = defaultIfEmpty( include.getGlob(), dirGlob );
+ startWalk( Paths.get( path ), glob, include.isRecursive(), collectedFiles, visitedDirs );
+ }
+
+ long walkKnownPathsFinished = System.currentTimeMillis() - start;
+
+ String message = processPlugins ? "enabled, values will be checked for presence in file system" : "disabled, "
+ + "only tags with attribute " + CACHE_INPUT_NAME + "=\"true\" will be added";
+ logInfo( "Scanning plugins configurations to find input files. Probing is " + message );
+
+ if ( processPlugins )
+ {
+ collectFromPlugins( collectedFiles, visitedDirs );
+ }
+ else
+ {
+ logInfo( "Skipping check plugins scan (probing is disabled by config)" );
+ }
+
+ long pluginsFinished = System.currentTimeMillis() - start - walkKnownPathsFinished;
+
+ TreeSet sorted = new TreeSet<>( fileComparator );
+ for ( Path collectedFile : collectedFiles )
+ {
+ sorted.add( collectedFile.normalize().toAbsolutePath() );
+ }
+
+ logInfo(
+ "Found " + sorted.size() + " input files. Project dir processing: " + walkKnownPathsFinished
+ + ", plugins: " + pluginsFinished + " millis" );
+ if ( logger.isDebugEnabled() )
+ {
+ logDebug( "Src input: " + sorted );
+ }
+
+ return sorted;
+ }
+
+ /**
+ * entry point for directory walk
+ */
+ private void startWalk( Path candidate,
+ String glob,
+ boolean recursive,
+ List collectedFiles,
+ Set visitedDirs )
+ {
+
+ Path normalized = candidate.isAbsolute() ? candidate : baseDirPath.resolve( candidate );
+ normalized = normalized.toAbsolutePath().normalize();
+ WalkKey key = new WalkKey( normalized, glob, recursive );
+ if ( visitedDirs.contains( key ) || !Files.exists( normalized ) )
+ {
+ return;
+ }
+
+ if ( Files.isDirectory( normalized ) )
+ {
+ if ( baseDirPath.startsWith( normalized ) )
+ { // requested to walk parent, can do only non recursive
+ key = new WalkKey( normalized, glob, false );
+ }
+ try
+ {
+ walkDir( key, collectedFiles, visitedDirs );
+ visitedDirs.add( key );
+ }
+ catch ( IOException e )
+ {
+ throw new RuntimeException( e );
+ }
+ }
+ else
+ {
+ if ( !isFilteredOutSubpath( normalized ) )
+ {
+ if ( logger.isDebugEnabled() )
+ {
+ logDebug( "Adding: " + normalized );
+ }
+ collectedFiles.add( normalized );
+ }
+ }
+ }
+
+ private Path normalizedPath( String directory )
+ {
+ return Paths.get( directory ).normalize();
+ }
+
+ private void collectFromPlugins( List files, HashSet visitedDirs )
+ {
+
+ List plugins = project.getBuild().getPlugins();
+ for ( Plugin plugin : plugins )
+ {
+
+ PluginScanConfig scanConfig = config.getPluginDirScanConfig( plugin );
+
+ if ( scanConfig.isSkip() )
+ {
+ logDebug( "Skipping plugin config scan (skip by config): " + plugin.getArtifactId() );
+ continue;
+ }
+
+ Xpp3Dom configuration = (Xpp3Dom) plugin.getConfiguration();
+ logDebug( "Processing plugin config: " + plugin.getArtifactId() );
+ if ( configuration != null )
+ {
+ addInputsFromPluginConfigs( configuration.getChildren(), scanConfig, files, visitedDirs );
+ }
+
+ for ( PluginExecution exec : plugin.getExecutions() )
+ {
+
+ final PluginScanConfig executionScanConfig = config.getExecutionDirScanConfig( plugin, exec );
+ PluginScanConfig mergedConfig = scanConfig.mergeWith( executionScanConfig );
+
+ if ( mergedConfig.isSkip() )
+ {
+ logDebug(
+ "Skipping plugin execution config scan (skip by config): "
+ + plugin.getArtifactId() + ", execId: " + exec.getId() );
+ continue;
+ }
+
+ Xpp3Dom execConfiguration = (Xpp3Dom) exec.getConfiguration();
+ logDebug( "Processing plugin: " + plugin.getArtifactId() + ", execution: " + exec.getId() );
+
+ if ( execConfiguration != null )
+ {
+ addInputsFromPluginConfigs( execConfiguration.getChildren(), mergedConfig, files, visitedDirs );
+ }
+ }
+ }
+ }
+
+ private Path walkDir( final WalkKey key,
+ final List collectedFiles,
+ final Set visitedDirs ) throws IOException
+ {
+ return Files.walkFileTree( key.getPath(), new SimpleFileVisitor()
+ {
+ @Override
+ public FileVisitResult preVisitDirectory( Path path,
+ BasicFileAttributes basicFileAttributes ) throws IOException
+ {
+ WalkKey currentDirKey = new WalkKey( path.toAbsolutePath().normalize(), key.getGlob(),
+ key.isRecursive() );
+ if ( isHidden( path ) )
+ {
+ if ( logger.isDebugEnabled() )
+ {
+ logDebug( "Skipping subtree (hidden): " + path );
+ }
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ else if ( isFilteredOutSubpath( path ) )
+ {
+ if ( logger.isDebugEnabled() )
+ {
+ logDebug( "Skipping subtree (blacklisted): " + path );
+ }
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ else if ( visitedDirs.contains( currentDirKey ) )
+ {
+ if ( logger.isDebugEnabled() )
+ {
+ logDebug( "Skipping subtree (visited): " + path );
+ }
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+
+ walkDirectoryFiles( path, collectedFiles, key.getGlob() );
+
+ if ( !key.isRecursive() )
+ {
+ if ( logger.isDebugEnabled() )
+ {
+ logDebug( "Skipping subtree (non recursive): " + path );
+ }
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+
+ if ( logger.isDebugEnabled() )
+ {
+ logDebug( "Visiting subtree: " + path );
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ } );
+ }
+
+ private void addInputsFromPluginConfigs( Xpp3Dom[] configurationChildren,
+ PluginScanConfig scanConfig,
+ List files, HashSet visitedDirs )
+ {
+
+ if ( configurationChildren == null )
+ {
+ return;
+ }
+
+ for ( Xpp3Dom configChild : configurationChildren )
+ {
+
+ String tagValue = configChild.getValue();
+ String tagName = configChild.getName();
+
+ if ( !scanConfig.accept( tagName ) )
+ {
+ logDebug( "Skipping property (scan config)): " + tagName + ", value: " + stripToEmpty( tagValue ) );
+ continue;
+ }
+
+ logDebug( "Checking xml tag. Tag: " + tagName + ", value: " + stripToEmpty( tagValue ) );
+
+ addInputsFromPluginConfigs( configChild.getChildren(), scanConfig, files, visitedDirs );
+
+ final ScanConfigProperties propertyConfig = scanConfig.getTagScanProperties( tagName );
+ final String glob = defaultIfEmpty( propertyConfig.getGlob(), dirGlob );
+ if ( "true".equals( configChild.getAttribute( CACHE_INPUT_NAME ) ) )
+ {
+ logInfo(
+ "Found tag marked with " + CACHE_INPUT_NAME + " attribute. Tag: " + tagName
+ + ", value: " + tagValue );
+ startWalk( Paths.get( tagValue ), glob, propertyConfig.isRecursive(), files, visitedDirs );
+ }
+ else
+ {
+ final Path candidate = getPathOrNull( tagValue );
+ if ( candidate != null )
+ {
+ startWalk( candidate, glob, propertyConfig.isRecursive(), files, visitedDirs );
+ if ( "descriptorRef".equals( tagName ) )
+ { // hardcoded logic for assembly plugin which could reference files omitting .xml suffix
+ startWalk( Paths.get( tagValue + ".xml" ), glob, propertyConfig.isRecursive(), files,
+ visitedDirs );
+ }
+ }
+ }
+ }
+ }
+
+ private Path getPathOrNull( String text )
+ {
+ // small optimization to not probe not-paths
+ boolean blacklisted = isBlank( text )
+ || equalsAnyIgnoreCase( text, "true", "false", "utf-8", "null", "\\" ) // common values
+ || contains( text, "*" ) // tag value is a glob or regex - unclear how to process
+ || ( contains( text, ":" ) && !contains( text, ":\\" ) )// artifactId
+ || startsWithAny( text, "com.", "org.", "io.", "java.", "javax." ) // java packages
+ || startsWithAny( text, "${env." ) // env variables in maven notation
+ || startsWithAny( text, "http:", "https:", "scm:", "ssh:", "git:", "svn:", "cp:",
+ "classpath:" ); // urls identified by common protocols
+ if ( !blacklisted )
+ {
+ try
+ {
+ return Paths.get( text );
+ }
+ catch ( Exception ignore )
+ {
+ }
+ }
+ if ( logger.isDebugEnabled() )
+ {
+ logDebug( text + ( blacklisted ? ": skipped(blacklisted literal)" : ": invalid path" ) );
+ }
+ return null;
+ }
+
+ private void logDebug( String message )
+ {
+ if ( logger.isDebugEnabled() )
+ {
+ logger.debug( "[CACHE][" + project.getArtifactId() + "] " + message );
+ }
+ }
+
+ private void logInfo( String message )
+ {
+ if ( logger.isInfoEnabled() )
+ {
+ logger.info( "[CACHE][" + project.getArtifactId() + "] " + message );
+ }
+ }
+
+ static void walkDirectoryFiles( Path dir, List collectedFiles, String glob )
+ {
+ if ( !Files.isDirectory( dir ) )
+ {
+ return;
+ }
+
+ try
+ {
+ try ( DirectoryStream stream = Files.newDirectoryStream( dir, glob ) )
+ {
+ for ( Path entry : stream )
+ {
+ File file = entry.toFile();
+ if ( file.isFile() && !isHidden( entry ) )
+ {
+ collectedFiles.add( entry );
+ }
+ }
+ }
+ }
+ catch ( IOException e )
+ {
+ throw new RuntimeException( "Cannot process directory: " + dir, e );
+ }
+ }
+
+ private static boolean isHidden( Path entry ) throws IOException
+ {
+ return Files.isHidden( entry ) || entry.toFile().getName().startsWith( "." );
+ }
+
+ private boolean isFilteredOutSubpath( Path path )
+ {
+ Path normalized = path.normalize();
+ for ( Path filteredOutDir : filteredOutPaths )
+ {
+ if ( normalized.startsWith( filteredOutDir ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private SortedMap getMutableDependencies() throws IOException
+ {
+ MultimoduleDiscoveryStrategy strategy = config.getMultimoduleDiscoveryStrategy();
+ SortedMap result = new TreeMap<>();
+
+ for ( Dependency dependency : project.getDependencies() )
+ {
+ // saved to index by the end of dependency build
+ final boolean currentlyBuilding = isBuilding( dependency, projectIndex );
+ final boolean partOfMultiModule = strategy.isPartOfMultiModule( dependency );
+ if ( !currentlyBuilding && !partOfMultiModule && !isSnapshot( dependency.getVersion() ) )
+ {
+ // external immutable dependency, should skip
+ continue;
+ }
+
+ if ( ProjectUtils.isPom( dependency ) )
+ {
+ // POM dependency will be resolved by maven system to actual dependencies
+ // and will contribute to effective pom.
+ // Effective result will be recorded by #getNormalizedPom
+ // so pom dependencies must be skipped as meaningless by themselves
+ continue;
+ }
+
+ final Artifact dependencyArtifact = repoSystem.createDependencyArtifact( dependency );
+ final String artifactKey = KeyUtils.getArtifactKey( dependencyArtifact );
+ DigestItemType resolved = null;
+ if ( currentlyBuilding )
+ {
+ resolved = projectArtifactsByKey.get( artifactKey );
+ if ( resolved == null )
+ {
+ throw new DependencyNotResolvedException( "Expected dependency not resolved: " + dependency );
+ }
+ }
+ else
+ {
+ if ( partOfMultiModule )
+ {
+ // TODO lookup in remote cache is not necessary for abfx, for versioned projects - make sense
+ final Optional bestMatchResult = localCache.findBestMatchingBuild( session, dependency );
+ if ( bestMatchResult.isPresent() )
+ {
+ final BuildInfo bestMatched = bestMatchResult.get();
+ resolved = bestMatched.findArtifact( dependency );
+ }
+ }
+ if ( resolved == null && !ProjectUtils.isPom( dependency ) )
+ {
+ try
+ {
+ resolved = resolveArtifact( dependencyArtifact, strategy );
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( "Cannot resolve dependency " + dependency, e );
+ }
+ }
+ }
+ result.put( artifactKey, resolved );
+ }
+ return result;
+ }
+
+ @Nonnull
+ private DigestItemType resolveArtifact( final Artifact dependencyArtifact,
+ MultimoduleDiscoveryStrategy strategy ) throws IOException
+ {
+
+ ArtifactResolutionRequest request = new ArtifactResolutionRequest().setArtifact(
+ dependencyArtifact ).setResolveRoot( true ).setResolveTransitively( false ).setLocalRepository(
+ session.getLocalRepository() ).setRemoteRepositories(
+ project.getRemoteArtifactRepositories() ).setOffline(
+ session.isOffline() || !strategy.isLookupRemoteMavenRepo( dependencyArtifact ) ).setForceUpdate(
+ session.getRequest().isUpdateSnapshots() ).setServers( session.getRequest().getServers() ).setMirrors(
+ session.getRequest().getMirrors() ).setProxies( session.getRequest().getProxies() );
+
+ final ArtifactResolutionResult result = repoSystem.resolve( request );
+
+ if ( !result.isSuccess() )
+ {
+ throw new DependencyNotResolvedException( "Cannot resolve in-project dependency: " + dependencyArtifact );
+ }
+
+ if ( !result.getMissingArtifacts().isEmpty() )
+ {
+ throw new DependencyNotResolvedException(
+ "Cannot resolve artifact: " + dependencyArtifact + ", missing: " + result.getMissingArtifacts() );
+ }
+
+ if ( result.getArtifacts().size() > 1 )
+ {
+ throw new IllegalStateException(
+ "Unexpected number of artifacts returned. Requested: " + dependencyArtifact
+ + ", expected: 1, actual: " + result.getArtifacts() );
+ }
+
+ final Artifact resolved = Iterables.getOnlyElement( result.getArtifacts() );
+
+ final HashAlgorithm algorithm = config.getHashFactory().createAlgorithm();
+ final String hash = algorithm.hash( resolved.getFile().toPath() );
+ return DtoUtils.createDigestedFile( resolved, hash );
+ }
+
+ /**
+ * PathIgnoringCaseComparator
+ */
+ public static class PathIgnoringCaseComparator implements Comparator
+ {
+ @Override
+ public int compare( Path f1, Path f2 )
+ {
+ String s1 = f1.toAbsolutePath().toString();
+ String s2 = f2.toAbsolutePath().toString();
+ if ( File.separator.equals( "\\" ) )
+ {
+ s1 = s1.replaceAll( "\\\\", "/" );
+ s2 = s2.replaceAll( "\\\\", "/" );
+ }
+ return s1.compareToIgnoreCase( s2 );
+ }
+ }
+
+ /**
+ * DependencyComparator
+ */
+ public static class DependencyComparator implements Comparator
+ {
+ @Override
+ public int compare( Dependency d1, Dependency d2 )
+ {
+ return d1.getArtifactId().compareTo( d2.getArtifactId() );
+ }
+ }
+
+ private List normalizePlugins( List plugins )
+ {
+ for ( Plugin plugin : plugins )
+ {
+ List excludeProperties = config.getEffectivePomExcludeProperties( plugin );
+ removeBlacklistedAttributes( (Xpp3Dom) plugin.getConfiguration(), excludeProperties );
+ for ( PluginExecution execution : plugin.getExecutions() )
+ {
+ Xpp3Dom config = (Xpp3Dom) execution.getConfiguration();
+ removeBlacklistedAttributes( config, excludeProperties );
+ }
+ Collections.sort( plugin.getDependencies(), dependencyComparator );
+ }
+ return plugins;
+ }
+
+ private void removeBlacklistedAttributes( Xpp3Dom node, List excludeProperties )
+ {
+ if ( node == null )
+ {
+ return;
+ }
+
+ Xpp3Dom[] children = node.getChildren();
+ for ( int i = 0; i < children.length; i++ )
+ {
+ Xpp3Dom child = children[i];
+ if ( excludeProperties.contains( child.getName() ) )
+ {
+ node.removeChild( i );
+ continue;
+ }
+ removeBlacklistedAttributes( child, excludeProperties );
+ }
+ }
+
+ public Logger getLogger()
+ {
+ return logger;
+ }
+
+ public CacheConfig getConfig()
+ {
+ return config;
+ }
+
+ public MavenSession getSession()
+ {
+ return session;
+ }
+
+ public MavenProject getProject()
+ {
+ return project;
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/checksum/MultimoduleDiscoveryStrategy.java b/maven-core/src/main/java/org/apache/maven/caching/checksum/MultimoduleDiscoveryStrategy.java
new file mode 100644
index 000000000000..b968f7764dca
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/checksum/MultimoduleDiscoveryStrategy.java
@@ -0,0 +1,33 @@
+package org.apache.maven.caching.checksum;
+
+/*
+ * 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.artifact.Artifact;
+import org.apache.maven.model.Dependency;
+
+/**
+ * MultimoduleDiscoveryStrategy
+ */
+public interface MultimoduleDiscoveryStrategy
+{
+ boolean isPartOfMultiModule( Dependency dependency );
+
+ boolean isLookupRemoteMavenRepo( Artifact dependency );
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/checksum/WalkKey.java b/maven-core/src/main/java/org/apache/maven/caching/checksum/WalkKey.java
new file mode 100644
index 000000000000..0d6f274df5b6
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/checksum/WalkKey.java
@@ -0,0 +1,95 @@
+package org.apache.maven.caching.checksum;
+
+/*
+ * 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.nio.file.Path;
+
+/**
+ * WalkKey
+ */
+public class WalkKey
+{
+ private final Path normalized;
+ private final String glob;
+ private final boolean recursive;
+
+ public WalkKey( Path normalized, String glob, boolean recursive )
+ {
+
+ this.normalized = normalized;
+ this.glob = glob;
+ this.recursive = recursive;
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o )
+ {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() )
+ {
+ return false;
+ }
+
+ WalkKey key = (WalkKey) o;
+
+ if ( recursive != key.recursive )
+ {
+ return false;
+ }
+ if ( !normalized.equals( key.normalized ) )
+ {
+ return false;
+ }
+ return glob.equals( key.glob );
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = normalized.hashCode();
+ result = 31 * result + glob.hashCode();
+ result = 31 * result + ( recursive ? 1 : 0 );
+ return result;
+ }
+
+ public Path getPath()
+ {
+ return normalized;
+ }
+
+ public String getGlob()
+ {
+ return glob;
+ }
+
+ public boolean isRecursive()
+ {
+ return recursive;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "WalkKey{" + "normalized=" + normalized + ", glob='" + glob + '\'' + ", recursive=" + recursive + '}';
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/CloseableBuffer.java b/maven-core/src/main/java/org/apache/maven/caching/hash/CloseableBuffer.java
new file mode 100644
index 000000000000..0fec3646ffa4
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/CloseableBuffer.java
@@ -0,0 +1,185 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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.IOException;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+import java.security.PrivilegedAction;
+
+import static java.security.AccessController.doPrivileged;
+import static org.apache.maven.caching.hash.ReflectionUtils.getField;
+import static org.apache.maven.caching.hash.ReflectionUtils.getMethod;
+
+/**
+ * CloseableBuffer https://stackoverflow.com/a/54046774
+ */
+public class CloseableBuffer implements AutoCloseable
+{
+ /* Java 8
+ private static final Cleaner CLEANER = doPrivileged((PrivilegedAction) () -> {
+ final boolean isOldJava = System.getProperty("java.specification.version", "9").startsWith("1.");
+ if (isOldJava) {
+ return DirectCleaner.isSupported() ? new DirectCleaner() : new NoopCleaner();
+ } else {
+ return UnsafeCleaner.isSupported() ? new UnsafeCleaner() : new NoopCleaner();
+ }
+ });
+ */
+ private static final Cleaner CLEANER = doPrivileged( new PrivilegedAction()
+ {
+ @Override
+ public Cleaner run()
+ {
+ return DirectCleaner.isSupported() ? new DirectCleaner() : new NoopCleaner();
+ }
+ } );
+
+ public static CloseableBuffer directBuffer( int capacity )
+ {
+ return new CloseableBuffer( ByteBuffer.allocateDirect( capacity ) );
+ }
+
+ public static CloseableBuffer mappedBuffer( FileChannel channel, MapMode mode ) throws IOException
+ {
+ return new CloseableBuffer( channel.map( mode, 0, channel.size() ) );
+ }
+
+ private ByteBuffer buffer;
+
+ /**
+ * Unmap only DirectByteBuffer and MappedByteBuffer
+ */
+ private CloseableBuffer( ByteBuffer buffer )
+ {
+ // Java 8: buffer.isDirect()
+ this.buffer = buffer;
+ }
+
+ /**
+ * Do not use buffer after close
+ */
+ public ByteBuffer getBuffer()
+ {
+ return buffer;
+ }
+
+ @Override
+ public void close()
+ {
+ // Java 8: () -> CLEANER.clean(buffer)
+ boolean done = doPrivileged( new PrivilegedAction()
+ {
+ @Override
+ public Boolean run()
+ {
+ return CLEANER.clean( buffer );
+ }
+ } );
+ if ( done )
+ {
+ buffer = null;
+ }
+ }
+
+ // Java 8: @FunctionalInterface
+ private interface Cleaner
+ {
+ boolean clean( ByteBuffer buffer );
+ }
+
+ private static class NoopCleaner implements Cleaner
+ {
+ @Override
+ public boolean clean( ByteBuffer buffer )
+ {
+ return false;
+ }
+ }
+
+ private static class DirectCleaner implements Cleaner
+ {
+ private static final Method ATTACHMENT = getMethod( "sun.nio.ch.DirectBuffer",
+ "attachment" );
+ private static final Method CLEANER = getMethod( "sun.nio.ch.DirectBuffer", "cleaner" );
+ private static final Method CLEAN = getMethod( "sun.misc.Cleaner", "clean" );
+
+ public static boolean isSupported()
+ {
+ return ATTACHMENT != null && CLEAN != null && CLEANER != null;
+ }
+
+ /**
+ * Make sure duplicates and slices are not cleaned, since this can result in duplicate attempts to clean the
+ * same buffer, which trigger a crash with: "A fatal error has been detected by the Java Runtime Environment:
+ * EXCEPTION_ACCESS_VIOLATION" See: https://stackoverflow.com/a/31592947/3950982
+ */
+ @Override
+ public boolean clean( ByteBuffer buffer )
+ {
+ try
+ {
+ if ( ATTACHMENT.invoke( buffer ) == null )
+ {
+ CLEAN.invoke( CLEANER.invoke( buffer ) );
+ return true;
+ }
+ }
+ catch ( Exception ignore )
+ {
+ }
+ return false;
+ }
+ }
+
+ private static class UnsafeCleaner implements Cleaner
+ {
+ // Java 9: getMethod("jdk.internal.misc.Unsafe", "invokeCleaner", ByteBuffer.class);
+ private static final Method INVOKE_CLEANER = getMethod( "sun.misc.Unsafe", "invokeCleaner", ByteBuffer.class );
+ private static final Object UNSAFE = getField( "sun.misc.Unsafe", "theUnsafe" );
+
+ public static boolean isSupported()
+ {
+ return UNSAFE != null && INVOKE_CLEANER != null;
+ }
+
+ /**
+ * Calling the above code in JDK9+ gives a reflection warning on stderr,
+ * Unsafe.theUnsafe.invokeCleaner(byteBuffer)
+ * makes the same call, but does not print the reflection warning
+ */
+ @Override
+ public boolean clean( ByteBuffer buffer )
+ {
+ try
+ {
+ // throws IllegalArgumentException if buffer is a duplicate or slice
+ INVOKE_CLEANER.invoke( UNSAFE, buffer );
+ return true;
+ }
+ catch ( Exception ignore )
+ {
+ }
+ return false;
+ }
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/Hash.java b/maven-core/src/main/java/org/apache/maven/caching/hash/Hash.java
new file mode 100644
index 000000000000..82220634cc6b
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/Hash.java
@@ -0,0 +1,61 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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.IOException;
+import java.nio.file.Path;
+
+/**
+ * Hash
+ */
+public class Hash
+{
+ /**
+ * Algorithm
+ */
+ public interface Algorithm
+ {
+ byte[] hash( byte[] array );
+
+ byte[] hash( Path path ) throws IOException;
+ }
+
+ /**
+ * accumulates states and should be completed by {@link #digest()}
+ */
+ public interface Checksum
+ {
+ void update( byte[] hash );
+
+ byte[] digest();
+ }
+
+ /**
+ * Factory
+ */
+ public interface Factory
+ {
+ String getAlgorithm();
+
+ Algorithm algorithm();
+
+ Checksum checksum( int count );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/HashAlgorithm.java b/maven-core/src/main/java/org/apache/maven/caching/hash/HashAlgorithm.java
new file mode 100644
index 000000000000..ec6ad68a053d
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/HashAlgorithm.java
@@ -0,0 +1,46 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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.IOException;
+import java.nio.file.Path;
+
+/**
+ * HashAlgorithm
+ */
+public class HashAlgorithm
+{
+ private final Hash.Algorithm algorithm;
+
+ HashAlgorithm( Hash.Algorithm algorithm )
+ {
+ this.algorithm = algorithm;
+ }
+
+ public String hash( Path path ) throws IOException
+ {
+ return HexUtils.encode( algorithm.hash( path ) );
+ }
+
+ public String hash( byte[] bytes )
+ {
+ return HexUtils.encode( algorithm.hash( bytes ) );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/HashChecksum.java b/maven-core/src/main/java/org/apache/maven/caching/hash/HashChecksum.java
new file mode 100644
index 000000000000..904077a6abae
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/HashChecksum.java
@@ -0,0 +1,67 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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.IOException;
+import java.nio.file.Path;
+
+/**
+ * HashChecksum
+ */
+public class HashChecksum
+{
+ private final Hash.Algorithm algorithm;
+ private final Hash.Checksum checksum;
+
+ HashChecksum( Hash.Algorithm algorithm, Hash.Checksum checksum )
+ {
+ this.algorithm = algorithm;
+ this.checksum = checksum;
+ }
+
+ public String update( Path path ) throws IOException
+ {
+ return updateAndEncode( algorithm.hash( path ) );
+ }
+
+ public String update( byte[] bytes )
+ {
+ return updateAndEncode( algorithm.hash( bytes ) );
+ }
+
+ /**
+ * @param hexHash hash value in hex format. This method doesn't accept generic text - could result in error
+ */
+ public String update( String hexHash )
+ {
+ return updateAndEncode( HexUtils.decode( hexHash ) );
+ }
+
+ private String updateAndEncode( byte[] hash )
+ {
+ checksum.update( hash );
+ return HexUtils.encode( hash );
+ }
+
+ public String digest()
+ {
+ return HexUtils.encode( checksum.digest() );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/HashFactory.java b/maven-core/src/main/java/org/apache/maven/caching/hash/HashFactory.java
new file mode 100644
index 000000000000..d610fceab924
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/HashFactory.java
@@ -0,0 +1,79 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * HashFactory
+ */
+public enum HashFactory
+{
+ SHA1( new SHA( "SHA-1" ) ),
+ SHA256( new SHA( "SHA-256" ) ),
+ SHA384( new SHA( "SHA-384" ) ),
+ SHA512( new SHA( "SHA-512" ) ),
+ XX( new XX() ),
+ XXMM( new XXMM() );
+
+ private static final Map LOOKUP = new HashMap<>();
+
+ static
+ {
+ for ( HashFactory factory : HashFactory.values() )
+ {
+ LOOKUP.put( factory.getAlgorithm(), factory );
+ }
+ }
+
+ public static HashFactory of( String algorithm ) throws NoSuchAlgorithmException
+ {
+ final HashFactory factory = LOOKUP.get( algorithm );
+ if ( factory == null )
+ {
+ throw new NoSuchAlgorithmException( algorithm );
+ }
+ return factory;
+ }
+
+ private final Hash.Factory factory;
+
+ HashFactory( Hash.Factory factory )
+ {
+ this.factory = factory;
+ }
+
+ public String getAlgorithm()
+ {
+ return factory.getAlgorithm();
+ }
+
+ public HashAlgorithm createAlgorithm()
+ {
+ return new HashAlgorithm( factory.algorithm() );
+ }
+
+ public HashChecksum createChecksum( int count )
+ {
+ return new HashChecksum( factory.algorithm(), factory.checksum( count ) );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/HexUtils.java b/maven-core/src/main/java/org/apache/maven/caching/hash/HexUtils.java
new file mode 100644
index 000000000000..f85d0f9c515c
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/HexUtils.java
@@ -0,0 +1,56 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.base.CharMatcher;
+import com.google.common.io.BaseEncoding;
+
+/**
+ * HexUtils
+ */
+public class HexUtils
+{
+
+ private static final BaseEncoding ENCODING = BaseEncoding.base16().lowerCase();
+ private static final CharMatcher MATCHER = CharMatcher.is( '0' );
+
+ public static String encode( byte[] hash )
+ {
+ return trimLeadingZero( ENCODING.encode( hash ) );
+ }
+
+ public static byte[] decode( String hex )
+ {
+ return ENCODING.decode( padLeadingZero( hex ) );
+ }
+
+ private static String trimLeadingZero( String hex )
+ {
+ String value = MATCHER.trimLeadingFrom( hex );
+ return value.isEmpty() ? "0" : value;
+ }
+
+ private static String padLeadingZero( String hex )
+ {
+ String value = hex.toLowerCase();
+ return value.length() % 2 == 0 ? value : "0" + value;
+ }
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/ReflectionUtils.java b/maven-core/src/main/java/org/apache/maven/caching/hash/ReflectionUtils.java
new file mode 100644
index 000000000000..259e6f0b7feb
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/ReflectionUtils.java
@@ -0,0 +1,61 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * ReflectionUtils
+ */
+class ReflectionUtils
+{
+ static Method getMethod( String className, String methodName, Class>... parameterTypes )
+ {
+ try
+ {
+ final Method method = Class.forName( className ).getMethod( methodName, parameterTypes );
+ method.setAccessible( true );
+ return method;
+ }
+ catch ( Exception ignore )
+ {
+ return null;
+ }
+ }
+
+ static Object getField( String className, String fieldName )
+ {
+ try
+ {
+ final Field field = Class.forName( className ).getDeclaredField( fieldName );
+ field.setAccessible( true );
+ return field.get( null );
+ }
+ catch ( Exception ignore )
+ {
+ return null;
+ }
+ }
+
+ private ReflectionUtils()
+ {
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/SHA.java b/maven-core/src/main/java/org/apache/maven/caching/hash/SHA.java
new file mode 100644
index 000000000000..e02dfe2f25e2
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/SHA.java
@@ -0,0 +1,103 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+
+/**
+ * SHA
+ */
+public class SHA implements Hash.Factory
+{
+ private static final ThreadLocal ALGORITHM = new ThreadLocal<>();
+ private static final ThreadLocal CHECKSUM = new ThreadLocal<>();
+
+ private final String algorithm;
+
+ SHA( String algorithm )
+ {
+ this.algorithm = algorithm;
+ }
+
+ @Override
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ @Override
+ public Hash.Algorithm algorithm()
+ {
+ return new SHA.Algorithm( ThreadLocalDigest.get( ALGORITHM, algorithm ) );
+ }
+
+ @Override
+ public Hash.Checksum checksum( int count )
+ {
+ return new SHA.Checksum( ThreadLocalDigest.get( CHECKSUM, algorithm ) );
+ }
+
+ private static class Algorithm implements Hash.Algorithm
+ {
+ private final MessageDigest digest;
+
+ private Algorithm( MessageDigest digest )
+ {
+ this.digest = digest;
+ }
+
+ @Override
+ public byte[] hash( byte[] array )
+ {
+ return digest.digest( array );
+ }
+
+ @Override
+ public byte[] hash( Path path ) throws IOException
+ {
+ return hash( Files.readAllBytes( path ) );
+ }
+ }
+
+ private static class Checksum implements Hash.Checksum
+ {
+ private final MessageDigest digest;
+
+ private Checksum( MessageDigest digest )
+ {
+ this.digest = digest;
+ }
+
+ @Override
+ public void update( byte[] hash )
+ {
+ digest.update( hash );
+ }
+
+ @Override
+ public byte[] digest()
+ {
+ return digest.digest();
+ }
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/ThreadLocalBuffer.java b/maven-core/src/main/java/org/apache/maven/caching/hash/ThreadLocalBuffer.java
new file mode 100644
index 000000000000..6d9f9d6269b7
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/ThreadLocalBuffer.java
@@ -0,0 +1,86 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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.nio.ByteBuffer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * ThreadLocalBuffer
+ */
+public class ThreadLocalBuffer
+{
+ private static final ConcurrentMap LOCALS = new ConcurrentHashMap<>();
+
+ public static ByteBuffer get( ThreadLocal local, int capacity )
+ {
+ final CloseableBuffer buffer = local.get();
+ if ( buffer == null )
+ {
+ return create( local, capacity );
+ }
+
+ if ( capacity( buffer ) < capacity )
+ {
+ close( buffer );
+ return create( local, capacity * 2 );
+ }
+
+ return clear( buffer );
+ }
+
+ @Override
+ public void finalize()
+ {
+ for ( CloseableBuffer buffer : LOCALS.keySet() )
+ {
+ buffer.close();
+ }
+ }
+
+ private static ByteBuffer create( ThreadLocal local, int capacity )
+ {
+ final CloseableBuffer buffer = CloseableBuffer.directBuffer( capacity );
+ local.set( buffer );
+ LOCALS.put( buffer, false );
+ return buffer.getBuffer();
+ }
+
+ private static int capacity( CloseableBuffer buffer )
+ {
+ return buffer.getBuffer().capacity();
+ }
+
+ private static ByteBuffer clear( CloseableBuffer buffer )
+ {
+ return (ByteBuffer) buffer.getBuffer().clear();
+ }
+
+ private static void close( CloseableBuffer buffer )
+ {
+ LOCALS.remove( buffer );
+ buffer.close();
+ }
+
+ private ThreadLocalBuffer()
+ {
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/ThreadLocalDigest.java b/maven-core/src/main/java/org/apache/maven/caching/hash/ThreadLocalDigest.java
new file mode 100644
index 000000000000..2df800e26f7a
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/ThreadLocalDigest.java
@@ -0,0 +1,71 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Objects;
+
+/**
+ * ThreadLocalDigest
+ */
+public class ThreadLocalDigest
+{
+ public static MessageDigest get( ThreadLocal local, String algorithm )
+ {
+ final MessageDigest digest = local.get();
+ if ( digest == null )
+ {
+ return create( local, algorithm );
+ }
+
+ if ( Objects.equals( digest.getAlgorithm(), algorithm ) )
+ {
+ return reset( digest );
+ }
+
+ reset( digest );
+ return create( local, algorithm );
+ }
+
+ private static MessageDigest create( ThreadLocal local, String algorithm )
+ {
+ try
+ {
+ final MessageDigest digest = MessageDigest.getInstance( algorithm );
+ local.set( digest );
+ return digest;
+ }
+ catch ( NoSuchAlgorithmException e )
+ {
+ throw new RuntimeException( "Cannot create message digest with algorithm: " + algorithm, e );
+ }
+ }
+
+ private static MessageDigest reset( MessageDigest digest )
+ {
+ digest.reset();
+ return digest;
+ }
+
+ private ThreadLocalDigest()
+ {
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/XX.java b/maven-core/src/main/java/org/apache/maven/caching/hash/XX.java
new file mode 100644
index 000000000000..24f9f4bff5e7
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/XX.java
@@ -0,0 +1,98 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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 net.openhft.hashing.LongHashFunction;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static com.google.common.primitives.Longs.toByteArray;
+
+/**
+ * XX
+ */
+public class XX implements Hash.Factory
+{
+ static final LongHashFunction INSTANCE = LongHashFunction.xx();
+
+ @Override
+ public String getAlgorithm()
+ {
+ return "XX";
+ }
+
+ @Override
+ public Hash.Algorithm algorithm()
+ {
+ return new XX.Algorithm();
+ }
+
+ @Override
+ public Hash.Checksum checksum( int count )
+ {
+ return new XX.Checksum( ByteBuffer.allocate( capacity( count ) ) );
+ }
+
+ static int capacity( int count )
+ {
+ // Java 8: Long.BYTES
+ return count * Long.SIZE / Byte.SIZE;
+ }
+
+ static class Algorithm implements Hash.Algorithm
+ {
+ @Override
+ public byte[] hash( byte[] array )
+ {
+ return toByteArray( INSTANCE.hashBytes( array ) );
+ }
+
+ @Override
+ public byte[] hash( Path path ) throws IOException
+ {
+ return hash( Files.readAllBytes( path ) );
+ }
+ }
+
+ static class Checksum implements Hash.Checksum
+ {
+ private final ByteBuffer buffer;
+
+ Checksum( ByteBuffer buffer )
+ {
+ this.buffer = buffer;
+ }
+
+ @Override
+ public void update( byte[] hash )
+ {
+ buffer.put( hash );
+ }
+
+ @Override
+ public byte[] digest()
+ {
+ return toByteArray( INSTANCE.hashBytes( buffer, 0, buffer.position() ) );
+ }
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/hash/XXMM.java b/maven-core/src/main/java/org/apache/maven/caching/hash/XXMM.java
new file mode 100644
index 000000000000..8e09299c247e
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/hash/XXMM.java
@@ -0,0 +1,67 @@
+package org.apache.maven.caching.hash;
+
+/*
+ * 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.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.file.Path;
+
+import static com.google.common.primitives.Longs.toByteArray;
+import static java.nio.channels.FileChannel.MapMode.READ_ONLY;
+import static java.nio.file.StandardOpenOption.READ;
+
+/**
+ * XXMM
+ */
+public class XXMM implements Hash.Factory
+{
+ private static final ThreadLocal BUFFER = new ThreadLocal<>();
+
+ @Override
+ public String getAlgorithm()
+ {
+ return "XXMM";
+ }
+
+ @Override
+ public Hash.Algorithm algorithm()
+ {
+ return new Algorithm();
+ }
+
+ @Override
+ public Hash.Checksum checksum( int count )
+ {
+ return new XX.Checksum( ThreadLocalBuffer.get( BUFFER, XX.capacity( count ) ) );
+ }
+
+ private static class Algorithm extends XX.Algorithm
+ {
+ @Override
+ public byte[] hash( Path path ) throws IOException
+ {
+ try ( FileChannel channel = FileChannel.open( path,
+ READ ); CloseableBuffer buffer = CloseableBuffer.mappedBuffer( channel, READ_ONLY ) )
+ {
+ return toByteArray( XX.INSTANCE.hashBytes( buffer.getBuffer() ) );
+ }
+ }
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/xml/AllExternalSrategy.java b/maven-core/src/main/java/org/apache/maven/caching/xml/AllExternalSrategy.java
new file mode 100644
index 000000000000..00c1d4d84ac8
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/xml/AllExternalSrategy.java
@@ -0,0 +1,42 @@
+package org.apache.maven.caching.xml;
+
+/*
+ * 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.artifact.Artifact;
+import org.apache.maven.caching.checksum.MultimoduleDiscoveryStrategy;
+import org.apache.maven.model.Dependency;
+
+/**
+ * AllExternalSrategy
+ */
+public class AllExternalSrategy implements MultimoduleDiscoveryStrategy
+{
+ @Override
+ public boolean isPartOfMultiModule( Dependency dependency )
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isLookupRemoteMavenRepo( Artifact artifact )
+ {
+ return true;
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/xml/BuildInfo.java b/maven-core/src/main/java/org/apache/maven/caching/xml/BuildInfo.java
new file mode 100644
index 000000000000..0b61bfd89d74
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/xml/BuildInfo.java
@@ -0,0 +1,273 @@
+package org.apache.maven.caching.xml;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.collect.Iterables;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.caching.ProjectUtils;
+import org.apache.maven.caching.checksum.MavenProjectInput;
+import org.apache.maven.caching.hash.HashAlgorithm;
+import org.apache.maven.caching.jaxb.ArtifactType;
+import org.apache.maven.caching.jaxb.BuildInfoType;
+import org.apache.maven.caching.jaxb.CompletedExecutionType;
+import org.apache.maven.caching.jaxb.DigestItemType;
+import org.apache.maven.caching.jaxb.ProjectsInputInfoType;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.plugin.MojoExecution;
+import org.codehaus.plexus.logging.Logger;
+import org.codehaus.plexus.util.StringUtils;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Objects;
+
+import static org.apache.maven.caching.ProjectUtils.isLaterPhase;
+import static org.apache.maven.caching.ProjectUtils.mojoExecutionKey;
+
+/**
+ * BuildInfo
+ */
+public class BuildInfo
+{
+
+ final BuildInfoType dto;
+ CacheSource source;
+
+ public BuildInfo( List goals,
+ ArtifactType artifact,
+ List attachedArtifacts,
+ ProjectsInputInfoType projectsInputInfo,
+ List completedExecutions,
+ String hashAlgorithm )
+ {
+ this.dto = new BuildInfoType();
+ this.dto.setCacheImplementationVersion( MavenProjectInput.CACHE_IMPLMENTATION_VERSION );
+ try
+ {
+ this.dto.setBuildTime( DatatypeFactory.newInstance().newXMLGregorianCalendar( new GregorianCalendar() ) );
+ }
+ catch ( DatatypeConfigurationException ignore )
+ {
+ }
+ try
+ {
+ this.dto.setBuildServer( InetAddress.getLocalHost().getCanonicalHostName() );
+ }
+ catch ( UnknownHostException ignore )
+ {
+ this.dto.setBuildServer( "unknown" );
+ }
+ this.dto.setHashFunction( hashAlgorithm );
+ this.dto.setArtifact( artifact );
+ this.dto.setGoals( createGoals( goals ) );
+ this.dto.setAttachedArtifacts( new BuildInfoType.AttachedArtifacts() );
+ this.dto.getAttachedArtifacts().getArtifact().addAll( attachedArtifacts );
+ this.dto.setExecutions( createExecutions( completedExecutions ) );
+ this.dto.setProjectsInputInfo( projectsInputInfo );
+ this.source = CacheSource.BUILD;
+ }
+
+ public CacheSource getSource()
+ {
+ return source;
+ }
+
+ private BuildInfoType.Executions createExecutions( List completedExecutions )
+ {
+ BuildInfoType.Executions executions = new BuildInfoType.Executions();
+ executions.getExecution().addAll( completedExecutions );
+ return executions;
+ }
+
+ public BuildInfo( BuildInfoType buildInfo, CacheSource source )
+ {
+ this.dto = buildInfo;
+ this.source = source;
+ }
+
+ public static BuildInfoType.Goals createGoals( List list )
+ {
+ BuildInfoType.Goals goals = new BuildInfoType.Goals();
+ goals.getGoal().addAll( list );
+ return goals;
+ }
+
+ public static BuildInfoType.AttachedArtifacts createAttachedArtifacts( List artifacts,
+ HashAlgorithm algorithm ) throws IOException
+ {
+ BuildInfoType.AttachedArtifacts attachedArtifacts = new BuildInfoType.AttachedArtifacts();
+ for ( Artifact artifact : artifacts )
+ {
+ final ArtifactType dto = DtoUtils.createDto( artifact );
+ if ( artifact.getFile() != null )
+ {
+ dto.setFileHash( algorithm.hash( artifact.getFile().toPath() ) );
+ }
+ attachedArtifacts.getArtifact().add( dto );
+ }
+ return attachedArtifacts;
+ }
+
+ public boolean isAllExecutionsPresent( List mojos, Logger logger )
+ {
+ for ( MojoExecution mojo : mojos )
+ {
+ // TODO for strict check we might want exact match
+ if ( !hasCompletedExecution( mojoExecutionKey( mojo ) ) )
+ {
+ logger.error( "Build mojo is not cached: " + mojo );
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean hasCompletedExecution( String mojoExecutionKey )
+ {
+ final List completedExecutions = dto.getExecutions().getExecution();
+ for ( CompletedExecutionType completedExecution : completedExecutions )
+ {
+ if ( StringUtils.equals( completedExecution.getExecutionKey(), mojoExecutionKey ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "BuildInfo{" + "dto=" + dto + '}';
+ }
+
+ public CompletedExecutionType findMojoExecutionInfo( MojoExecution mojoExecution )
+ {
+
+ if ( !dto.isSetExecutions() )
+ {
+ return null;
+ }
+
+ final List executions = dto.getExecutions().getExecution();
+ for ( CompletedExecutionType execution : executions )
+ {
+ if ( StringUtils.equals( execution.getExecutionKey(), mojoExecutionKey( mojoExecution ) ) )
+ {
+ return execution;
+ }
+ }
+ return null;
+ }
+
+ public String getCacheImplementationVersion()
+ {
+ return dto.getCacheImplementationVersion();
+ }
+
+ public ArtifactType getArtifact()
+ {
+ return dto.getArtifact();
+ }
+
+ public List getAttachedArtifacts()
+ {
+ if ( dto.isSetAttachedArtifacts() )
+ {
+ return dto.getAttachedArtifacts().getArtifact();
+ }
+ return Collections.emptyList();
+ }
+
+ public BuildInfoType getDto()
+ {
+ return dto;
+ }
+
+ public String getHighestCompletedGoal()
+ {
+ return Iterables.getLast( dto.getGoals().getGoal() );
+ }
+
+ public List getCachedSegment( List mojoExecutions )
+ {
+ List list = new ArrayList<>();
+ for ( MojoExecution mojoExecution : mojoExecutions )
+ {
+ if ( !isLaterPhase( mojoExecution.getLifecyclePhase(), "post-clean" ) )
+ {
+ continue;
+ }
+ if ( isLaterPhase( mojoExecution.getLifecyclePhase(), getHighestCompletedGoal() ) )
+ {
+ break;
+ }
+ list.add( mojoExecution );
+ }
+ return list;
+
+ }
+
+ public List getPostCachedSegment( List mojoExecutions )
+ {
+ List list = new ArrayList<>();
+ for ( MojoExecution mojoExecution : mojoExecutions )
+ {
+ if ( isLaterPhase( mojoExecution.getLifecyclePhase(), getHighestCompletedGoal() ) )
+ {
+ list.add( mojoExecution );
+ }
+ }
+ return list;
+ }
+
+ public DigestItemType findArtifact( Dependency dependency )
+ {
+
+ if ( ProjectUtils.isPom( dependency ) )
+ {
+ throw new IllegalArgumentException( "Pom dependencies should not be treated as artifacts: " + dependency );
+ }
+ List artifacts = new ArrayList<>( getAttachedArtifacts() );
+ artifacts.add( getArtifact() );
+ for ( ArtifactType artifact : artifacts )
+ {
+ if ( isEquals( dependency, artifact ) )
+ {
+ return DtoUtils.createdDigestedByProjectChecksum( artifact, dto.getProjectsInputInfo().getChecksum() );
+ }
+ }
+ return null;
+ }
+
+ private boolean isEquals( Dependency dependency, ArtifactType artifact )
+ {
+ return Objects.equals( dependency.getGroupId(), artifact.getArtifactId() ) && Objects.equals(
+ dependency.getArtifactId(), artifact.getArtifactId() ) && Objects.equals( dependency.getType(),
+ artifact.getType() ) && Objects.equals( dependency.getClassifier(), artifact.getClassifier() );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/xml/CacheConfig.java b/maven-core/src/main/java/org/apache/maven/caching/xml/CacheConfig.java
new file mode 100644
index 000000000000..2f5137d9a3ea
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/xml/CacheConfig.java
@@ -0,0 +1,108 @@
+package org.apache.maven.caching.xml;
+
+/*
+ * 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.caching.PluginScanConfig;
+import org.apache.maven.caching.checksum.MultimoduleDiscoveryStrategy;
+import org.apache.maven.caching.hash.HashFactory;
+import org.apache.maven.caching.jaxb.PathSetType;
+import org.apache.maven.caching.jaxb.PropertyNameType;
+import org.apache.maven.caching.jaxb.TrackedPropertyType;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginExecution;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.project.MavenProject;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * CacheConfig
+ */
+public interface CacheConfig
+{
+
+ CacheState initialize( MavenProject project, MavenSession session );
+
+ @Nonnull
+ List getTrackedProperties( MojoExecution mojoExecution );
+
+ boolean isLogAllProperties( MojoExecution mojoExecution );
+
+ @Nonnull
+ List getLoggedProperties( MojoExecution mojoExecution );
+
+ @Nonnull
+ List getNologProperties( MojoExecution mojoExecution );
+
+ @Nonnull
+ List getEffectivePomExcludeProperties( Plugin plugin );
+
+ String isProcessPlugins();
+
+ String getDefaultGlob();
+
+ @Nonnull
+ List getGlobalIncludePaths();
+
+ @Nonnull
+ List getGlobalExcludePaths();
+
+ @Nonnull
+ PluginScanConfig getPluginDirScanConfig( Plugin plugin );
+
+ @Nonnull
+ PluginScanConfig getExecutionDirScanConfig( Plugin plugin, PluginExecution exec );
+
+ @Nonnull
+ MultimoduleDiscoveryStrategy getMultimoduleDiscoveryStrategy();
+
+ @Nonnull
+ HashFactory getHashFactory();
+
+ boolean isForcedExecution( MojoExecution execution );
+
+ String getUrl();
+
+ boolean isEnabled();
+
+ boolean isRemoteCacheEnabled();
+
+ boolean isSaveToRemote();
+
+ boolean isSaveFinal();
+
+ boolean isFailFast();
+
+ int getMaxLocalBuildsCached();
+
+ List getAttachedOutputs();
+
+ boolean canIgnore( MojoExecution mojoExecution );
+
+ @Nonnull
+ List getExcludePatterns();
+
+ boolean isBaselineDiffEnabled();
+
+ String getBaselineCacheUrl();
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/xml/CacheConfigImpl.java b/maven-core/src/main/java/org/apache/maven/caching/xml/CacheConfigImpl.java
new file mode 100644
index 000000000000..9dd0e85f578f
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/xml/CacheConfigImpl.java
@@ -0,0 +1,579 @@
+package org.apache.maven.caching.xml;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.caching.DefaultPluginScanConfig;
+import org.apache.maven.caching.PluginScanConfig;
+import org.apache.maven.caching.PluginScanConfigImpl;
+import org.apache.maven.caching.checksum.MultimoduleDiscoveryStrategy;
+import org.apache.maven.caching.hash.HashFactory;
+import org.apache.maven.caching.jaxb.CacheType;
+import org.apache.maven.caching.jaxb.ConfigurationType;
+import org.apache.maven.caching.jaxb.CoordinatesBaseType;
+import org.apache.maven.caching.jaxb.ExecutablesType;
+import org.apache.maven.caching.jaxb.ExecutionConfigurationScanType;
+import org.apache.maven.caching.jaxb.ExecutionControlType;
+import org.apache.maven.caching.jaxb.ExecutionIdsListType;
+import org.apache.maven.caching.jaxb.GoalReconciliationType;
+import org.apache.maven.caching.jaxb.GoalsListType;
+import org.apache.maven.caching.jaxb.PathSetType;
+import org.apache.maven.caching.jaxb.PluginConfigurationScanType;
+import org.apache.maven.caching.jaxb.PluginSetType;
+import org.apache.maven.caching.jaxb.PropertyNameType;
+import org.apache.maven.caching.jaxb.TrackedPropertyType;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginExecution;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
+
+import javax.annotation.Nonnull;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.Boolean.TRUE;
+import static java.lang.Boolean.parseBoolean;
+import static org.apache.maven.caching.ProjectUtils.getMultimoduleRoot;
+
+/**
+ * CacheConfigImpl
+ */
+@Component( role = CacheConfig.class,
+ instantiationStrategy = "singleton" )
+public class CacheConfigImpl implements CacheConfig
+{
+
+ public static final String CONFIG_PATH_PROPERTY_NAME = "remote.cache.configPath";
+ public static final String CACHE_ENABLED_PROPERTY_NAME = "remote.cache.enabled";
+ public static final String SAVE_TO_REMOTE_PROPERTY_NAME = "remote.cache.save.enabled";
+ public static final String SAVE_NON_OVERRIDEABLE_NAME = "remote.cache.save.final";
+ public static final String FAIL_FAST_PROPERTY_NAME = "remote.cache.failFast";
+ public static final String BASELINE_BUILD_URL_PROPERTY_NAME = "remote.cache.baselineUrl";
+
+ @Requirement
+ private Logger logger;
+
+ @Requirement
+ private XmlService xmlService;
+
+ private volatile CacheState state = CacheState.NOT_INITIALIZED;
+ private volatile CacheType cacheConfig;
+ private volatile HashFactory hashFactory;
+
+ private final Supplier> excludePatterns = Suppliers.memoize( new Supplier>()
+ {
+ @Override
+ public List get()
+ {
+ return compileExcludePatterns();
+ }
+ } );
+
+
+ @Override
+ public synchronized CacheState initialize( MavenProject project, MavenSession session )
+ {
+
+ if ( state != CacheState.NOT_INITIALIZED )
+ {
+ return state;
+ }
+
+ final String enabled = System.getProperty( CACHE_ENABLED_PROPERTY_NAME, "true" );
+ if ( !parseBoolean( enabled ) )
+ {
+ logger.info( "Cache disabled by command line flag, project will be built fully and not cached" );
+ state = CacheState.DISABLED;
+ return state;
+ }
+
+ Path configPath = null;
+
+ String configPathText = System.getProperty( CONFIG_PATH_PROPERTY_NAME );
+ if ( StringUtils.isNotBlank( configPathText ) )
+ {
+ configPath = Paths.get( configPathText );
+ }
+ if ( configPath == null )
+ {
+ configPathText = project.getProperties().getProperty( CONFIG_PATH_PROPERTY_NAME );
+ if ( StringUtils.isNotBlank( configPathText ) )
+ {
+ configPath = Paths.get( configPathText );
+ }
+ }
+
+ if ( configPath == null )
+ {
+ configPath = Paths.get( getMultimoduleRoot( session ), ".mvn", "maven-cache-config.xml" );
+ }
+
+ if ( !Files.exists( configPath ) )
+ {
+ logger.warn(
+ "Cache configuration is not available at configured path " + configPath + ", cache is disabled" );
+ state = CacheState.DISABLED;
+ return state;
+ }
+
+ try
+ {
+ logger.info( "Loading cache configuration from " + configPath );
+ cacheConfig = xmlService.fromFile( CacheType.class, configPath.toFile() );
+ }
+ catch ( Exception e )
+ {
+ throw new IllegalArgumentException(
+ "Cannot initialize cache because xml config is not valid or not available", e );
+ }
+
+ if ( !cacheConfig.getConfiguration().isEnabled() )
+ {
+ state = CacheState.DISABLED;
+ return state;
+ }
+
+ String hashAlgorithm = null;
+ try
+ {
+ hashAlgorithm = getConfiguration().getHashAlgorithm();
+ hashFactory = HashFactory.of( hashAlgorithm );
+ logger.info( "Using " + hashAlgorithm + " hash algorithm for cache" );
+ }
+ catch ( Exception e )
+ {
+ throw new IllegalArgumentException( "Unsupported hashing algorithm: " + hashAlgorithm, e );
+ }
+
+ state = CacheState.INITIALIZED;
+ return state;
+ }
+
+ @Nonnull
+ @Override
+ public List getTrackedProperties( MojoExecution mojoExecution )
+ {
+ checkInitializedState();
+ final GoalReconciliationType reconciliationConfig = findReconciliationConfig( mojoExecution );
+ if ( reconciliationConfig != null )
+ {
+ return reconciliationConfig.getReconcile();
+ }
+ else
+ {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public boolean isLogAllProperties( MojoExecution mojoExecution )
+ {
+ final GoalReconciliationType reconciliationConfig = findReconciliationConfig( mojoExecution );
+ if ( reconciliationConfig != null && reconciliationConfig.isLogAll() )
+ {
+ return true;
+ }
+ return cacheConfig.isSetExecutionControl() && cacheConfig.getExecutionControl().isSetReconcile()
+ && cacheConfig.getExecutionControl().getReconcile().isLogAllProperties();
+ }
+
+ private GoalReconciliationType findReconciliationConfig( MojoExecution mojoExecution )
+ {
+
+ if ( !cacheConfig.isSetExecutionControl() )
+ {
+ return null;
+ }
+
+ final ExecutionControlType executionControl = cacheConfig.getExecutionControl();
+ if ( !executionControl.isSetReconcile() )
+ {
+ return null;
+ }
+
+ final List reconciliation = executionControl.getReconcile().getPlugin();
+
+ for ( GoalReconciliationType goalReconciliationConfig : reconciliation )
+ {
+
+ final String goal = mojoExecution.getGoal();
+
+ if ( isPluginMatch( mojoExecution.getPlugin(), goalReconciliationConfig ) && StringUtils.equals( goal,
+ goalReconciliationConfig.getGoal() ) )
+ {
+ return goalReconciliationConfig;
+ }
+ }
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public List getLoggedProperties( MojoExecution mojoExecution )
+ {
+ checkInitializedState();
+
+ final GoalReconciliationType reconciliationConfig = findReconciliationConfig( mojoExecution );
+ if ( reconciliationConfig != null )
+ {
+ return reconciliationConfig.getLog();
+ }
+ else
+ {
+ return Collections.emptyList();
+ }
+ }
+
+ @Nonnull
+ @Override
+ public List getNologProperties( MojoExecution mojoExecution )
+ {
+ checkInitializedState();
+ final GoalReconciliationType reconciliationConfig = findReconciliationConfig( mojoExecution );
+ if ( reconciliationConfig != null )
+ {
+ return reconciliationConfig.getNolog();
+ }
+ else
+ {
+ return Collections.emptyList();
+ }
+ }
+
+ @Nonnull
+ @Override
+ public List getEffectivePomExcludeProperties( Plugin plugin )
+ {
+ checkInitializedState();
+ final PluginConfigurationScanType pluginConfig = findPluginScanConfig( plugin );
+
+ if ( pluginConfig != null && pluginConfig.isSetEffectivePom() )
+ {
+ return pluginConfig.getEffectivePom().getExcludeProperty();
+ }
+ return Collections.emptyList();
+ }
+
+ private PluginConfigurationScanType findPluginScanConfig( Plugin plugin )
+ {
+
+ if ( !cacheConfig.isSetInput() )
+ {
+ return null;
+ }
+
+ final List pluginConfigs = cacheConfig.getInput().getPlugin();
+ for ( PluginConfigurationScanType pluginConfig : pluginConfigs )
+ {
+ if ( isPluginMatch( plugin, pluginConfig ) )
+ {
+ return pluginConfig;
+ }
+ }
+ return null;
+ }
+
+ private boolean isPluginMatch( Plugin plugin, CoordinatesBaseType pluginConfig )
+ {
+ return StringUtils.equals( pluginConfig.getArtifactId(),
+ plugin.getArtifactId() ) && ( !pluginConfig.isSetGroupId() || StringUtils.equals(
+ pluginConfig.getGroupId(), plugin.getGroupId() ) );
+ }
+
+
+ @Nonnull
+ @Override
+ public PluginScanConfig getPluginDirScanConfig( Plugin plugin )
+ {
+ checkInitializedState();
+ final PluginConfigurationScanType pluginConfig = findPluginScanConfig( plugin );
+ if ( pluginConfig == null || !pluginConfig.isSetDirScan() )
+ {
+ return new DefaultPluginScanConfig();
+ }
+
+ return new PluginScanConfigImpl( pluginConfig.getDirScan() );
+ }
+
+ @Nonnull
+ @Override
+ public PluginScanConfig getExecutionDirScanConfig( Plugin plugin, PluginExecution exec )
+ {
+ checkInitializedState();
+ final PluginConfigurationScanType pluginScanConfig = findPluginScanConfig( plugin );
+
+ if ( pluginScanConfig != null )
+ {
+ final ExecutionConfigurationScanType executionScanConfig = findExecutionScanConfig( exec,
+ pluginScanConfig.getExecution() );
+ if ( executionScanConfig != null && executionScanConfig.isSetDirScan() )
+ {
+ return new PluginScanConfigImpl( executionScanConfig.getDirScan() );
+ }
+ }
+
+ return new DefaultPluginScanConfig();
+ }
+
+ private ExecutionConfigurationScanType findExecutionScanConfig( PluginExecution execution,
+ List scanConfigs )
+ {
+ for ( ExecutionConfigurationScanType executionScanConfig : scanConfigs )
+ {
+ if ( executionScanConfig.getExecId().contains( execution.getId() ) )
+ {
+ return executionScanConfig;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String isProcessPlugins()
+ {
+ checkInitializedState();
+ return TRUE.toString();
+ }
+
+ @Override
+ public String getDefaultGlob()
+ {
+ checkInitializedState();
+ return StringUtils.trim( cacheConfig.getInput().getGlobal().getGlob() );
+ }
+
+ @Nonnull
+ @Override
+ public List getGlobalIncludePaths()
+ {
+ checkInitializedState();
+ return cacheConfig.getInput().getGlobal().getInclude();
+ }
+
+ @Nonnull
+ @Override
+ public List getGlobalExcludePaths()
+ {
+ checkInitializedState();
+ return cacheConfig.getInput().getGlobal().getExclude();
+ }
+
+ @Nonnull
+ @Override
+ public MultimoduleDiscoveryStrategy getMultimoduleDiscoveryStrategy()
+ {
+ checkInitializedState();
+ final ConfigurationType.ProjectDiscoveryStrategy projectDiscoveryStrategy =
+ cacheConfig.getConfiguration().getProjectDiscoveryStrategy();
+ if ( projectDiscoveryStrategy.isSetSpecificVersion() )
+ {
+ return new SentinelVersionStartegy( projectDiscoveryStrategy.getSpecificVersion() );
+ }
+ return new AllExternalSrategy();
+ }
+
+ @Nonnull
+ @Override
+ public HashFactory getHashFactory()
+ {
+ checkInitializedState();
+ return hashFactory;
+ }
+
+ @Override
+ public boolean canIgnore( MojoExecution mojoExecution )
+ {
+ checkInitializedState();
+ if ( !cacheConfig.isSetExecutionControl() || !cacheConfig.getExecutionControl().isSetIgnoreMissing() )
+ {
+ return false;
+ }
+
+ return executionMatches( mojoExecution, cacheConfig.getExecutionControl().getIgnoreMissing() );
+ }
+
+ @Override
+ public boolean isForcedExecution( MojoExecution execution )
+ {
+ checkInitializedState();
+ if ( !cacheConfig.isSetExecutionControl() || !cacheConfig.getExecutionControl().isSetRunAlways() )
+ {
+ return false;
+ }
+
+ return executionMatches( execution, cacheConfig.getExecutionControl().getRunAlways() );
+ }
+
+ private boolean executionMatches( MojoExecution execution, ExecutablesType executablesType )
+ {
+ final List pluginConfigs = executablesType.getPlugin();
+ for ( PluginSetType pluginConfig : pluginConfigs )
+ {
+ if ( isPluginMatch( execution.getPlugin(), pluginConfig ) )
+ {
+ return true;
+ }
+ }
+
+ final List executionIds = executablesType.getExecution();
+ for ( ExecutionIdsListType executionConfig : executionIds )
+ {
+ if ( isPluginMatch( execution.getPlugin(), executionConfig ) && executionConfig.getExecId().contains(
+ execution.getExecutionId() ) )
+ {
+ return true;
+ }
+ }
+
+ final List pluginsGoalsList = executablesType.getGoals();
+ for ( GoalsListType pluginGoals : pluginsGoalsList )
+ {
+ if ( isPluginMatch( execution.getPlugin(), pluginGoals ) && pluginGoals.getGoal().contains(
+ execution.getGoal() ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled()
+ {
+ return state == CacheState.INITIALIZED;
+ }
+
+
+ @Override
+ public boolean isRemoteCacheEnabled()
+ {
+ checkInitializedState();
+ return getRemote().isEnabled();
+ }
+
+ @Override
+ public boolean isSaveToRemote()
+ {
+ checkInitializedState();
+ return Boolean.getBoolean( SAVE_TO_REMOTE_PROPERTY_NAME ) || getRemote().isSaveToRemote();
+ }
+
+ @Override
+ public boolean isSaveFinal()
+ {
+ return Boolean.getBoolean( SAVE_NON_OVERRIDEABLE_NAME );
+ }
+
+ @Override
+ public boolean isFailFast()
+ {
+ return Boolean.getBoolean( FAIL_FAST_PROPERTY_NAME );
+ }
+
+ @Override
+ public boolean isBaselineDiffEnabled()
+ {
+ return System.getProperties().containsKey( BASELINE_BUILD_URL_PROPERTY_NAME );
+ }
+
+ @Override
+ public String getBaselineCacheUrl()
+ {
+ return System.getProperty( BASELINE_BUILD_URL_PROPERTY_NAME );
+ }
+
+ @Override
+ public String getUrl()
+ {
+ checkInitializedState();
+ return getRemote().getUrl();
+ }
+
+
+ @Override
+ public int getMaxLocalBuildsCached()
+ {
+ checkInitializedState();
+ return getLocal().getMaxBuildsCached().intValue();
+ }
+
+ @Override
+ public List getAttachedOutputs()
+ {
+ checkInitializedState();
+ final ConfigurationType.AttachedOutputs attachedOutputs = getConfiguration().getAttachedOutputs();
+ return attachedOutputs == null ? Collections.emptyList() : attachedOutputs.getDirName();
+ }
+
+ @Nonnull
+ @Override
+ public List getExcludePatterns()
+ {
+ checkInitializedState();
+ return excludePatterns.get();
+ }
+
+ private List compileExcludePatterns()
+ {
+ if ( cacheConfig.isSetOutput() && cacheConfig.getOutput().isSetExclude() )
+ {
+ List patterns = new ArrayList<>();
+ for ( String pattern : cacheConfig.getOutput().getExclude().getPattern() )
+ {
+ patterns.add( Pattern.compile( pattern ) );
+ }
+ return patterns;
+ }
+ return Collections.emptyList();
+ }
+
+ private ConfigurationType.Remote getRemote()
+ {
+ return getConfiguration().getRemote();
+ }
+
+ private ConfigurationType.Local getLocal()
+ {
+ return getConfiguration().getLocal();
+ }
+
+ private ConfigurationType getConfiguration()
+ {
+ return cacheConfig.getConfiguration();
+ }
+
+ private void checkInitializedState()
+ {
+ checkState( state == CacheState.INITIALIZED, "Cache is not initialized. Actual state: " + state );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/xml/CacheSource.java b/maven-core/src/main/java/org/apache/maven/caching/xml/CacheSource.java
new file mode 100644
index 000000000000..b21944463632
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/xml/CacheSource.java
@@ -0,0 +1,30 @@
+package org.apache.maven.caching.xml;
+
+/*
+ * 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.
+ */
+
+/**
+ * CacheSource
+ */
+public enum CacheSource
+{
+ LOCAL,
+ REMOTE,
+ BUILD
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/xml/CacheState.java b/maven-core/src/main/java/org/apache/maven/caching/xml/CacheState.java
new file mode 100644
index 000000000000..99267ed01e89
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/xml/CacheState.java
@@ -0,0 +1,30 @@
+package org.apache.maven.caching.xml;
+
+/*
+ * 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.
+ */
+
+/**
+ * CacheState
+ */
+public enum CacheState
+{
+ NOT_INITIALIZED,
+ DISABLED,
+ INITIALIZED
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/xml/DtoUtils.java b/maven-core/src/main/java/org/apache/maven/caching/xml/DtoUtils.java
new file mode 100644
index 000000000000..a2810ab86824
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/xml/DtoUtils.java
@@ -0,0 +1,219 @@
+package org.apache.maven.caching.xml;
+
+/*
+ * 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.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.caching.ProjectUtils;
+import org.apache.maven.caching.jaxb.ArtifactType;
+import org.apache.maven.caching.jaxb.CompletedExecutionType;
+import org.apache.maven.caching.jaxb.DigestItemType;
+import org.apache.maven.caching.jaxb.PropertyValueType;
+import org.apache.maven.caching.jaxb.TrackedPropertyType;
+import org.apache.maven.model.Dependency;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+
+import static org.apache.maven.caching.checksum.KeyUtils.getArtifactKey;
+
+/**
+ * DtoUtils
+ */
+public class DtoUtils
+{
+
+ public static String findPropertyValue( String propertyName, CompletedExecutionType completedExecution )
+ {
+ final CompletedExecutionType.Configuration configuration = completedExecution.getConfiguration();
+ if ( configuration == null )
+ {
+ return null;
+ }
+ final List properties = configuration.getProperty();
+ for ( PropertyValueType property : properties )
+ {
+ if ( StringUtils.equals( propertyName, property.getName() ) )
+ {
+ return property.getValue();
+ }
+ }
+ return null;
+ }
+
+ public static ArtifactType createDto( Artifact artifact )
+ {
+ ArtifactType dto = new ArtifactType();
+ dto.setArtifactId( artifact.getArtifactId() );
+ dto.setGroupId( artifact.getGroupId() );
+ dto.setVersion( artifact.getVersion() );
+ dto.setClassifier( artifact.getClassifier() );
+ dto.setType( artifact.getType() );
+ dto.setScope( artifact.getScope() );
+ dto.setFileName( ProjectUtils.normalizedName( artifact ) );
+ return dto;
+ }
+
+ public static DigestItemType createdDigestedByProjectChecksum( ArtifactType artifact, String projectChecksum )
+ {
+ DigestItemType dit = new DigestItemType();
+ dit.setType( "module" );
+ dit.setHash( projectChecksum );
+ dit.setFileChecksum( artifact.getFileHash() );
+ dit.setValue( getArtifactKey( artifact ) );
+ return dit;
+ }
+
+ public static DigestItemType createDigestedFile( Artifact artifact, String fileHash )
+ {
+ DigestItemType dit = new DigestItemType();
+ dit.setType( "artifact" );
+ dit.setHash( fileHash );
+ dit.setFileChecksum( fileHash );
+ dit.setValue( getArtifactKey( artifact ) );
+ return dit;
+ }
+
+ public static Dependency createDependency( ArtifactType artifact )
+ {
+ final Dependency dependency = new Dependency();
+ dependency.setArtifactId( artifact.getArtifactId() );
+ dependency.setGroupId( artifact.getGroupId() );
+ dependency.setVersion( artifact.getVersion() );
+ dependency.setClassifier( artifact.getClassifier() );
+ dependency.setType( artifact.getType() );
+ dependency.setScope( artifact.getScope() );
+ return dependency;
+ }
+
+ public static Dependency createDependency( Artifact artifact )
+ {
+ final Dependency dependency = new Dependency();
+ dependency.setArtifactId( artifact.getArtifactId() );
+ dependency.setGroupId( artifact.getGroupId() );
+ dependency.setVersion( artifact.getVersion() );
+ dependency.setType( artifact.getType() );
+ dependency.setScope( artifact.getScope() );
+ dependency.setClassifier( artifact.getClassifier() );
+ return dependency;
+ }
+
+ public static void addProperty( CompletedExecutionType execution,
+ String propertyName,
+ Object value,
+ String baseDirPath,
+ boolean tracked )
+ {
+ if ( execution.getConfiguration() == null )
+ {
+ execution.setConfiguration( new CompletedExecutionType.Configuration() );
+ }
+ final PropertyValueType valueType = new PropertyValueType();
+ valueType.setName( propertyName );
+ if ( value != null && value.getClass().isArray() )
+ {
+ value = ArrayUtils.toString( value );
+ }
+ final String valueText = String.valueOf( value );
+ valueType.setValue( StringUtils.remove( valueText, baseDirPath ) );
+ valueType.setTracked( tracked );
+ execution.getConfiguration().getProperty().add( valueType );
+ }
+
+ public static boolean containsAllProperties(
+ @Nonnull CompletedExecutionType cachedExecution, List trackedProperties )
+ {
+
+ if ( trackedProperties == null || trackedProperties.isEmpty() )
+ {
+ return true;
+ }
+
+ if ( !cachedExecution.isSetConfiguration() )
+ {
+ return false;
+ }
+
+ final List executionProperties = cachedExecution.getConfiguration().getProperty();
+ for ( TrackedPropertyType trackedProperty : trackedProperties )
+ {
+ if ( !contains( executionProperties, trackedProperty.getPropertyName() ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean contains( List executionProperties, String propertyName )
+ {
+ for ( PropertyValueType executionProperty : executionProperties )
+ {
+ if ( StringUtils.equals( executionProperty.getName(), propertyName ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static ArtifactType copy( ArtifactType artifact )
+ {
+ ArtifactType copy = new ArtifactType();
+ if ( artifact.isSetArtifactId() )
+ {
+ copy.setArtifactId( artifact.getArtifactId() );
+ }
+ if ( artifact.isSetGroupId() )
+ {
+ copy.setGroupId( artifact.getGroupId() );
+ }
+ if ( artifact.isSetVersion() )
+ {
+ copy.setVersion( artifact.getVersion() );
+ }
+ if ( artifact.isSetType() )
+ {
+ copy.setType( artifact.getType() );
+ }
+ if ( artifact.isSetClassifier() )
+ {
+ copy.setClassifier( artifact.getClassifier() );
+ }
+ if ( artifact.isSetScope() )
+ {
+ copy.setScope( artifact.getScope() );
+ }
+ if ( artifact.isSetFileName() )
+ {
+ copy.setFileName( artifact.getFileName() );
+ }
+ if ( artifact.isSetFileHash() )
+ {
+ copy.setFileHash( artifact.getFileHash() );
+ }
+ if ( artifact.isSetFileSize() )
+ {
+ copy.setFileSize( artifact.getFileSize() );
+ }
+ return copy;
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/xml/SentinelVersionStartegy.java b/maven-core/src/main/java/org/apache/maven/caching/xml/SentinelVersionStartegy.java
new file mode 100644
index 000000000000..6d332308cc07
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/xml/SentinelVersionStartegy.java
@@ -0,0 +1,51 @@
+package org.apache.maven.caching.xml;
+
+/*
+ * 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.artifact.Artifact;
+import org.apache.maven.caching.checksum.MultimoduleDiscoveryStrategy;
+import org.apache.maven.model.Dependency;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * SentinelVersionStartegy
+ */
+public class SentinelVersionStartegy implements MultimoduleDiscoveryStrategy
+{
+ private final String version;
+
+ public SentinelVersionStartegy( String version )
+ {
+ this.version = version;
+ }
+
+ @Override
+ public boolean isPartOfMultiModule( Dependency dependency )
+ {
+ return StringUtils.equals( version, dependency.getVersion() );
+ }
+
+ @Override
+ public boolean isLookupRemoteMavenRepo( Artifact artifact )
+ {
+ // TODO abfx specific - should be config driven
+ return !StringUtils.equals( version, artifact.getVersion() );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/caching/xml/XmlService.java b/maven-core/src/main/java/org/apache/maven/caching/xml/XmlService.java
new file mode 100644
index 000000000000..658c9d0dd3b1
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/caching/xml/XmlService.java
@@ -0,0 +1,145 @@
+package org.apache.maven.caching.xml;
+
+/*
+ * 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.caching.jaxb.BuildDiffType;
+import org.apache.maven.caching.jaxb.BuildInfoType;
+import org.apache.maven.caching.jaxb.CacheReportType;
+import org.apache.maven.caching.jaxb.ObjectFactory;
+import org.codehaus.plexus.component.annotations.Component;
+import org.xml.sax.SAXException;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+
+/**
+ * XmlService
+ */
+@Component( role = XmlService.class )
+public class XmlService
+{
+
+ private final ObjectFactory objectFactory;
+ private final JAXBContext jaxbContext;
+ private final Schema schema;
+
+ public XmlService() throws JAXBException, SAXException
+ {
+ objectFactory = new ObjectFactory();
+ jaxbContext = JAXBContext.newInstance( "org.apache.maven.caching.jaxb", XmlService.class.getClassLoader() );
+
+ SchemaFactory sf = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
+ final InputStream domainSchemaStream = getResourceAsStream( "cache-domain.xsd" );
+ final Source domainSchema = new StreamSource( domainSchemaStream );
+ final InputStream configSchemaStream = getResourceAsStream( "cache-config.xsd" );
+ final Source configSchema = new StreamSource( configSchemaStream );
+ schema = sf.newSchema( new Source[] {domainSchema, configSchema} );
+ }
+
+ public byte[] toBytes( BuildInfoType buildInfo )
+ {
+ return serializeXml( objectFactory.createBuild( buildInfo ) );
+ }
+
+ public byte[] toBytes( BuildDiffType diff )
+ {
+ return serializeXml( objectFactory.createDiff( diff ) );
+ }
+
+ public byte[] toBytes( CacheReportType cacheReportType )
+ {
+
+ return serializeXml( objectFactory.createReport( cacheReportType ) );
+ }
+
+ private byte[] serializeXml( JAXBElement> element )
+ {
+ try
+ {
+ Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
+ jaxbMarshaller.setSchema( schema );
+ // output pretty printed
+ jaxbMarshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true );
+ jaxbMarshaller.setProperty( Marshaller.JAXB_ENCODING, "UTF-8" );
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ jaxbMarshaller.marshal( element, baos );
+ return baos.toByteArray();
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( "Errors in jaxb serialization: " + e.toString(), e );
+ }
+ }
+
+ public T fromFile( Class clazz, File file )
+ {
+
+ try
+ {
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ unmarshaller.setSchema( schema );
+ JAXBElement result = (JAXBElement) unmarshaller.unmarshal( file );
+ return result.getValue();
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( "Errors in jaxb serialization: " + e.toString(), e );
+ }
+ }
+
+ public static InputStream getResourceAsStream( String name )
+ {
+ ClassLoader cl = XmlService.class.getClassLoader();
+ if ( cl == null )
+ {
+ // A system class.
+ return ClassLoader.getSystemResourceAsStream( name );
+ }
+ return cl.getResourceAsStream( name );
+ }
+
+ public T fromBytes( Class clazz, byte[] bytes )
+ {
+ try
+ {
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ unmarshaller.setSchema( schema );
+ JAXBElement result = (JAXBElement) unmarshaller.unmarshal( new ByteArrayInputStream( bytes ) );
+ return result.getValue();
+
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( "Errors in jaxb serialization: " + e.toString(), e );
+ }
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
index fb7a9f45064d..5a7db543f80b 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
@@ -34,9 +34,11 @@
import org.apache.maven.MavenExecutionException;
import org.apache.maven.ProjectCycleException;
import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.caching.checksum.KeyUtils;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.ProjectDependencyGraph;
+import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.building.DefaultModelProblem;
import org.apache.maven.model.building.ModelProblem;
@@ -56,6 +58,8 @@
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.dag.CycleDetectedException;
+import static org.apache.maven.artifact.versioning.VersionRange.createFromVersion;
+
/**
* Builds the {@link ProjectDependencyGraph inter-dependencies graph} between projects in the reactor.
*/
@@ -64,6 +68,8 @@ public class DefaultGraphBuilder
implements GraphBuilder
{
+ public static final String PROJECT_VERSION_PROP_NAME = "org.maven.project.version";
+
@Requirement
private Logger logger;
@@ -81,6 +87,11 @@ public Result build( MavenSession session )
{
final List projects = getProjectsForMavenReactor( session );
validateProjects( projects );
+
+ if ( System.getProperties().containsKey( PROJECT_VERSION_PROP_NAME ) )
+ {
+ overrideReactorVersions( projects, session );
+ }
result = reactorDependencyGraph( session, projects );
}
@@ -100,6 +111,68 @@ public Result build( MavenSession session )
}
}
+ private void overrideReactorVersions( List projects, MavenSession session )
+ {
+ String injectedVersion = System.getProperty( PROJECT_VERSION_PROP_NAME );
+ logger.info( "Overriding reactor projects version to " + injectedVersion );
+
+ Map reactorProjects = new HashMap<>( projects.size() );
+
+ for ( MavenProject project : projects )
+ {
+ String projectKey = KeyUtils.getVersionlessProjectKey( project );
+ logger.debug(
+ "[" + projectKey + "] Overriding version from " + project.getVersion() + " to " + injectedVersion );
+ reactorProjects.put( projectKey, project.getVersion() );
+ project.setVersion( injectedVersion );
+ project.getArtifact().setVersionRange( createFromVersion( injectedVersion ) );
+ project.getArtifact().updateVersion( injectedVersion, session.getLocalRepository() );
+ }
+
+ for ( MavenProject project : projects )
+ {
+ String projectKey = KeyUtils.getVersionlessProjectKey( project );
+ MavenProject parent = project.getParent();
+ String parentKey = KeyUtils.getVersionlessProjectKey( parent );
+ String overriddenParentVersion = reactorProjects.get( parentKey );
+ if ( overriddenParentVersion != null && overriddenParentVersion.equals(
+ project.getParentArtifact().getVersion() ) )
+ {
+ logger.debug(
+ "[" + projectKey + "] Parent " + parentKey + " overriding artefact version from "
+ + parent.getVersion() + " to " + injectedVersion );
+ project.getParentArtifact().setVersionRange( createFromVersion( injectedVersion ) );
+ project.getParentArtifact().updateVersion( injectedVersion, session.getLocalRepository() );
+ }
+
+ for ( Dependency dependency : project.getDependencies() )
+ {
+ String dependencyKey = KeyUtils.getVersionlessDependencyKey( dependency );
+ String overriddenReactorVersion = reactorProjects.get( dependencyKey );
+ if ( overriddenReactorVersion != null && overriddenReactorVersion.equals( dependency.getVersion() ) )
+ {
+ logger.debug(
+ "[" + projectKey + "] Dependency " + dependencyKey + " overriding version from "
+ + dependency.getVersion() + " to " + injectedVersion );
+ dependency.setVersion( injectedVersion );
+ }
+ }
+
+ for ( Dependency dependency : project.getDependencyManagement().getDependencies() )
+ {
+ String dependencyKey = KeyUtils.getVersionlessDependencyKey( dependency );
+ String overriddenReactorVersion = reactorProjects.get( dependencyKey );
+ if ( overriddenReactorVersion != null && overriddenReactorVersion.equals( dependency.getVersion() ) )
+ {
+ logger.debug(
+ "[" + projectKey + "] Dependency management " + dependencyKey
+ + " overriding version from " + dependency.getVersion() + " to " + injectedVersion );
+ dependency.setVersion( injectedVersion );
+ }
+ }
+ }
+ }
+
private Result sessionDependencyGraph( final MavenSession session )
throws CycleDetectedException, DuplicateProjectException
{
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java
index 7ee499f4b1a0..41004bdb118c 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java
@@ -31,13 +31,13 @@
* Context of dependency artifacts for a particular project.
*
* NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
- *
+ *
* @since 3.0
* @author Benjamin Bentmann
* @author Kristian Rosenvold (class extract only)
*/
// TODO From a concurrency perspective, this class is not good. The combination of mutable/immutable state is not nice
-public class DependencyContext
+public class DependencyContext implements IDependencyContext
{
private static final Collection> UNRESOLVED = Arrays.asList();
@@ -66,46 +66,53 @@ public DependencyContext( MavenProject project, Collection scopesToColle
scopesToResolveForAggregatedProjects = Collections.synchronizedSet( new TreeSet() );
}
+ @Override
public MavenProject getProject()
{
return project;
}
+ @Override
public Collection getScopesToCollectForCurrentProject()
{
return scopesToCollectForCurrentProject;
}
+ @Override
public Collection getScopesToResolveForCurrentProject()
{
return scopesToResolveForCurrentProject;
}
+ @Override
public Collection getScopesToCollectForAggregatedProjects()
{
return scopesToCollectForAggregatedProjects;
}
+ @Override
public Collection getScopesToResolveForAggregatedProjects()
{
return scopesToResolveForAggregatedProjects;
}
+ @Override
public boolean isResolutionRequiredForCurrentProject()
{
- return lastDependencyArtifacts != project.getDependencyArtifacts() || ( lastDependencyArtifacts != null
- && lastDependencyArtifactCount != lastDependencyArtifacts.size() );
+ return lastDependencyArtifacts != project.getDependencyArtifacts()
+ || ( lastDependencyArtifacts != null && lastDependencyArtifactCount != lastDependencyArtifacts.size() );
}
+ @Override
public boolean isResolutionRequiredForAggregatedProjects( Collection scopesToCollect,
Collection scopesToResolve )
{
- boolean required =
- scopesToCollectForAggregatedProjects.addAll( scopesToCollect )
- || scopesToResolveForAggregatedProjects.addAll( scopesToResolve );
+ boolean required = scopesToCollectForAggregatedProjects.addAll(
+ scopesToCollect ) || scopesToResolveForAggregatedProjects.addAll( scopesToResolve );
return required;
}
+ @Override
public void synchronizeWithProjectState()
{
lastDependencyArtifacts = project.getDependencyArtifacts();
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/IDependencyContext.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/IDependencyContext.java
new file mode 100644
index 000000000000..1f81561b1c7f
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/IDependencyContext.java
@@ -0,0 +1,47 @@
+package org.apache.maven.lifecycle.internal;
+
+/*
+ * 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.project.MavenProject;
+
+import java.util.Collection;
+
+/**
+ * IDependencyContext
+ */
+public interface IDependencyContext
+{
+ MavenProject getProject();
+
+ Collection getScopesToCollectForCurrentProject();
+
+ Collection getScopesToResolveForCurrentProject();
+
+ Collection getScopesToCollectForAggregatedProjects();
+
+ Collection getScopesToResolveForAggregatedProjects();
+
+ boolean isResolutionRequiredForCurrentProject();
+
+ boolean isResolutionRequiredForAggregatedProjects( Collection scopesToCollect,
+ Collection scopesToResolve );
+
+ void synchronizeWithProjectState();
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
index b78f54dc42f3..59f384983d9e 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
@@ -22,13 +22,23 @@
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.CumulativeScopeArtifactFilter;
+import org.apache.maven.caching.CacheController;
+import org.apache.maven.caching.CacheResult;
+import org.apache.maven.caching.MojoExecutionManager;
+import org.apache.maven.caching.MojoParametersListener;
+import org.apache.maven.caching.xml.BuildInfo;
+import org.apache.maven.caching.xml.CacheConfig;
+import org.apache.maven.caching.xml.CacheState;
import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.MavenSession;
+import org.apache.maven.execution.MojoExecutionEvent;
+import org.apache.maven.execution.MojoExecutionListener;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.lifecycle.MissingProjectException;
import org.apache.maven.plugin.BuildPluginManager;
import org.apache.maven.plugin.MavenPluginManager;
import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.MojoExecution.Source;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.PluginConfigurationException;
@@ -38,6 +48,7 @@
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.StringUtils;
import java.util.ArrayList;
@@ -48,6 +59,13 @@
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.apache.maven.caching.ProjectUtils.isLaterPhase;
+import static org.apache.maven.caching.checksum.KeyUtils.getVersionlessProjectKey;
+import static org.apache.maven.caching.xml.CacheState.DISABLED;
+import static org.apache.maven.caching.xml.CacheState.INITIALIZED;
+
/**
*