From 8af0a674db7cf1199d62e1cba60e29f84a144129 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sun, 14 Nov 2021 10:14:54 +0100 Subject: [PATCH 01/37] [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 | 6 +++--- 15 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml index 1c979bce60d0..6e12bb0e4d4c 100644 --- a/apache-maven/pom.xml +++ b/apache-maven/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT apache-maven diff --git a/maven-artifact/pom.xml b/maven-artifact/pom.xml index 2ddb8c761aa3..0ced0ebe53f0 100644 --- a/maven-artifact/pom.xml +++ b/maven-artifact/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-artifact diff --git a/maven-builder-support/pom.xml b/maven-builder-support/pom.xml index d33e3b1e9eda..9851384a8034 100644 --- a/maven-builder-support/pom.xml +++ b/maven-builder-support/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-builder-support diff --git a/maven-compat/pom.xml b/maven-compat/pom.xml index d95264559ccf..c3715e6298be 100644 --- a/maven-compat/pom.xml +++ b/maven-compat/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-compat diff --git a/maven-core/pom.xml b/maven-core/pom.xml index 32fb86fb8313..ab8c71379277 100644 --- a/maven-core/pom.xml +++ b/maven-core/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-core diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml index f732b8957d40..c180c865ea66 100644 --- a/maven-embedder/pom.xml +++ b/maven-embedder/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-embedder diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml index 485553de88c8..bf0b0f9f256a 100644 --- a/maven-model-builder/pom.xml +++ b/maven-model-builder/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-model-builder diff --git a/maven-model/pom.xml b/maven-model/pom.xml index 007ecbcdaf65..db70815c092a 100644 --- a/maven-model/pom.xml +++ b/maven-model/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-model diff --git a/maven-plugin-api/pom.xml b/maven-plugin-api/pom.xml index 0c399f4a83c0..ab836127524a 100644 --- a/maven-plugin-api/pom.xml +++ b/maven-plugin-api/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-plugin-api diff --git a/maven-repository-metadata/pom.xml b/maven-repository-metadata/pom.xml index 9caa582bc7d7..31c0418b0c98 100644 --- a/maven-repository-metadata/pom.xml +++ b/maven-repository-metadata/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-repository-metadata diff --git a/maven-resolver-provider/pom.xml b/maven-resolver-provider/pom.xml index cb3c950035a1..62ff3f26c60c 100644 --- a/maven-resolver-provider/pom.xml +++ b/maven-resolver-provider/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-resolver-provider diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml index 3a53bd97cb40..6391cf223fd1 100644 --- a/maven-settings-builder/pom.xml +++ b/maven-settings-builder/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-settings-builder diff --git a/maven-settings/pom.xml b/maven-settings/pom.xml index b2e5ef895f5e..36dd1923ab1f 100644 --- a/maven-settings/pom.xml +++ b/maven-settings/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-settings diff --git a/maven-slf4j-provider/pom.xml b/maven-slf4j-provider/pom.xml index e848870a9c8b..d12d0aedffba 100644 --- a/maven-slf4j-provider/pom.xml +++ b/maven-slf4j-provider/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.4 + 3.8.5-SNAPSHOT maven-slf4j-provider diff --git a/pom.xml b/pom.xml index e739a027b0d9..5704043efefe 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ under the License. maven - 3.8.4 + 3.8.5-SNAPSHOT pom Apache Maven @@ -77,7 +77,7 @@ under the License. ref/3-LATEST None **/package-info.java - 2021-11-14T09:12:47Z + 2021-11-14T09:14:52Z @@ -101,7 +101,7 @@ under the License. scm:git:https://gitbox.apache.org/repos/asf/maven.git scm:git:https://gitbox.apache.org/repos/asf/maven.git https://github.com/apache/maven/tree/${project.scm.tag} - maven-3.8.4 + maven-3.8.3 jira From ed3279809cad6c77cd8e5c217230c612d1222d9a Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sun, 3 Oct 2021 18:47:20 +0200 Subject: [PATCH 02/37] Update DOAP with Maven 3.8.3 release --- doap_Maven.rdf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doap_Maven.rdf b/doap_Maven.rdf index 531df1217a61..1a1f8edb036f 100644 --- a/doap_Maven.rdf +++ b/doap_Maven.rdf @@ -33,6 +33,15 @@ under the License. Latest stable release + 2021-09-27 + 3.8.3 + http://archive.apache.org/dist/maven/maven-3/3.8.3/binaries/apache-maven-3.8.3-bin.zip + http://archive.apache.org/dist/maven/maven-3/3.8.3/binaries/apache-maven-3.8.3-bin.tar.gz + http://archive.apache.org/dist/maven/maven-3/3.8.3/source/apache-maven-3.8.3-src.zip + http://archive.apache.org/dist/maven/maven-3/3.8.3/source/apache-maven-3.8.3-src.tar.gz + + + Apache Maven 3.8.2 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 From f568170e361ee2f448227ec4c2bce5a2ab2aa99d Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sat, 20 Nov 2021 15:55:23 +0100 Subject: [PATCH 03/37] Update DOAP with Maven 3.8.4 release --- doap_Maven.rdf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doap_Maven.rdf b/doap_Maven.rdf index 1a1f8edb036f..07185589da38 100644 --- a/doap_Maven.rdf +++ b/doap_Maven.rdf @@ -33,6 +33,15 @@ under the License. Latest stable release + 2021-11-14 + 3.8.4 + http://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.zip + http://archive.apache.org/dist/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz + http://archive.apache.org/dist/maven/maven-3/3.8.4/source/apache-maven-3.8.4-src.zip + http://archive.apache.org/dist/maven/maven-3/3.8.4/source/apache-maven-3.8.4-src.tar.gz + + + Apache Maven 3.8.3 2021-09-27 3.8.3 http://archive.apache.org/dist/maven/maven-3/3.8.3/binaries/apache-maven-3.8.3-bin.zip From 5bc395fd08719f221e10998db13475110d510651 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 1 Dec 2021 19:42:20 +0100 Subject: [PATCH 04/37] Add github checks to maven-3.8.x branch --- .github/workflows/maven.yml | 147 ++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 000000000000..addba89d6393 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,147 @@ +# 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. + +name: Java CI + +on: [push, pull_request] + +jobs: + build: + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + fail-fast: false + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + java-version: 8 + distribution: 'temurin' + cache: 'maven' + + - name: Build with Maven + run: mvn verify -e -B -V -DdistributionFileName=apache-maven + + - name: Upload built Maven + uses: actions/upload-artifact@v2 + if: ${{ matrix.os == 'ubuntu-latest' }} + with: + name: built-maven + path: apache-maven/target/ + + - name: Upload built Apache Maven Wrapper + uses: actions/upload-artifact@v2 + if: ${{ matrix.os == 'ubuntu-latest' }} + with: + name: built-apache-maven-wrapper + path: apache-maven-wrapper/target/ + + - name: Upload built Maven Wrapper + uses: actions/upload-artifact@v2 + if: ${{ matrix.os == 'ubuntu-latest' }} + with: + name: built-maven-wrapper + path: maven-wrapper/target/maven-wrapper.jar + + integration-test: + needs: build + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + java: [8, 11, 17] + + fail-fast: false + runs-on: ${{ matrix.os }} + + steps: + - name: Collect environment context variables + shell: bash + env: + PR_HEAD_LABEL: ${{ github.event.pull_request.head.label }} + run: | + set +e + repo=maven-integration-testing + target_branch=master + target_user=apache + if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then + user=${PR_HEAD_LABEL%:*} + branch=${PR_HEAD_LABEL#*:} + else + user=${GITHUB_REPOSITORY%/*} + branch=${GITHUB_REF#refs/heads/} + fi + if [ $branch != "master" ]; then + git ls-remote https://github.com/$user/$repo.git | grep "refs/heads/${branch}$" > /dev/null + if [ $? -eq 0 ]; then + echo "Found a branch \"$branch\" in fork \"$user/$repo\", configuring this for the integration tests to be run against." + target_branch=$branch + target_user=$user + else + echo "Could not find fork \"$user/$repo\" or a branch \"$branch\" in this fork. Falling back to \"$target_branch\" in \"$target_user/$repo\"." + fi + else + echo "Integration tests will run against $target_user/$repo for master builds." + fi + echo "REPO_BRANCH=$target_branch" >> $GITHUB_ENV + echo "REPO_USER=$target_user" >> $GITHUB_ENV + + - name: Checkout maven-integration-testing + uses: actions/checkout@v2 + with: + repository: ${{ env.REPO_USER }}/maven-integration-testing + path: maven-integration-testing/ + ref: ${{ env.REPO_BRANCH }} + + - name: Set up cache for ~/.m2/repository + uses: actions/cache@v2 + with: + path: ~/.m2/repository + key: it-m2-repo-${{ matrix.os }}-${{ hashFiles('maven-integration-testing/**/pom.xml') }} + restore-keys: | + it-m2-repo-${{ matrix.os }}- + + - name: Download built Maven + uses: actions/download-artifact@v2 + with: + name: built-maven + path: built-maven/ + + - name: Download built Apache Maven Wrapper + uses: actions/download-artifact@v2 + with: + name: built-apache-maven-wrapper + path: built-apache-maven-wrapper/ + + - name: Download built Maven Wrapper + uses: actions/download-artifact@v2 + with: + name: built-maven-wrapper + path: built-maven-wrapper/ + + - name: Set up JDK + uses: actions/setup-java@v2 + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + cache: 'maven' + + - name: Running integration tests + shell: bash + run: mvn install -e -B -V -Prun-its,embedded -Dmaven.repo.local="$HOME/.m2/repository" -DmavenDistro="$GITHUB_WORKSPACE/built-maven/apache-maven-bin.zip" -DwrapperDistroDir="$GITHUB_WORKSPACE/built-apache-maven-wrapper/" -DmavenWrapper="$GITHUB_WORKSPACE/built-maven-wrapper/maven-wrapper.jar" -f maven-integration-testing/pom.xml From 803c2155548f7d985e2f7afeb36f29761b5b1b49 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 2 Dec 2021 08:36:32 +0100 Subject: [PATCH 05/37] Fix github checks --- .github/workflows/maven.yml | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index addba89d6393..3b82ac148897 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -46,20 +46,6 @@ jobs: name: built-maven path: apache-maven/target/ - - name: Upload built Apache Maven Wrapper - uses: actions/upload-artifact@v2 - if: ${{ matrix.os == 'ubuntu-latest' }} - with: - name: built-apache-maven-wrapper - path: apache-maven-wrapper/target/ - - - name: Upload built Maven Wrapper - uses: actions/upload-artifact@v2 - if: ${{ matrix.os == 'ubuntu-latest' }} - with: - name: built-maven-wrapper - path: maven-wrapper/target/maven-wrapper.jar - integration-test: needs: build strategy: @@ -123,18 +109,6 @@ jobs: name: built-maven path: built-maven/ - - name: Download built Apache Maven Wrapper - uses: actions/download-artifact@v2 - with: - name: built-apache-maven-wrapper - path: built-apache-maven-wrapper/ - - - name: Download built Maven Wrapper - uses: actions/download-artifact@v2 - with: - name: built-maven-wrapper - path: built-maven-wrapper/ - - name: Set up JDK uses: actions/setup-java@v2 with: @@ -144,4 +118,4 @@ jobs: - name: Running integration tests shell: bash - run: mvn install -e -B -V -Prun-its,embedded -Dmaven.repo.local="$HOME/.m2/repository" -DmavenDistro="$GITHUB_WORKSPACE/built-maven/apache-maven-bin.zip" -DwrapperDistroDir="$GITHUB_WORKSPACE/built-apache-maven-wrapper/" -DmavenWrapper="$GITHUB_WORKSPACE/built-maven-wrapper/maven-wrapper.jar" -f maven-integration-testing/pom.xml + run: mvn install -e -B -V -Prun-its,embedded -Dmaven.repo.local="$HOME/.m2/repository" -DmavenDistro="$GITHUB_WORKSPACE/built-maven/apache-maven-bin.zip" -f maven-integration-testing/pom.xml From 10a72f30f7bdd19e803820a215383b975a5283ce Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 17 Dec 2021 08:42:18 +0100 Subject: [PATCH 06/37] [MNG-7156][MNG-7285] Add locking in MojoExecutor (#628) --- .../lifecycle/internal/MojoExecutor.java | 91 +++++++++++++++++++ .../maven/project/ProjectBuilderTest.java | 13 +++ 2 files changed, 104 insertions(+) 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..cf97c8cab954 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 @@ -39,6 +39,7 @@ import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.util.StringUtils; +import org.eclipse.aether.SessionData; import java.util.ArrayList; import java.util.Arrays; @@ -48,6 +49,12 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** *

@@ -76,6 +83,8 @@ public class MojoExecutor @Requirement private ExecutionEventCatapult eventCatapult; + private final ReadWriteLock aggregatorLock = new ReentrantReadWriteLock(); + public MojoExecutor() { } @@ -197,6 +206,88 @@ private void execute( MavenSession session, MojoExecution mojoExecution, Project } } + try ( ProjectLock lock = new ProjectLock( session, mojoDescriptor, aggregatorLock ) ) + { + doExecute( session, mojoExecution, projectIndex, dependencyContext ); + } + } + + /** + * Aggregating mojo executions (possibly) modify all MavenProjects, including those that are currently in use + * by concurrently running mojo executions. To prevent race conditions, an aggregating execution will block + * all other executions until finished. + * We also lock on a given project to forbid a forked lifecycle to be executed concurrently with the project. + * TODO: ideally, the builder should take care of the ordering in a smarter way + * TODO: and concurrency issues fixed with MNG-7157 + */ + private static class ProjectLock implements AutoCloseable + { + final Lock acquiredAggregatorLock; + final Lock acquiredProjectLock; + + ProjectLock( MavenSession session, MojoDescriptor mojoDescriptor, ReadWriteLock aggregatorLock ) + { + if ( session.getRequest().getDegreeOfConcurrency() > 1 ) + { + boolean aggregator = mojoDescriptor.isAggregator(); + acquiredAggregatorLock = aggregator ? aggregatorLock.writeLock() : aggregatorLock.readLock(); + acquiredProjectLock = getProjectLock( session ); + acquiredAggregatorLock.lock(); + acquiredProjectLock.lock(); + } + else + { + acquiredAggregatorLock = null; + acquiredProjectLock = null; + } + } + + @Override + public void close() + { + // release the lock in the reverse order of the acquisition + if ( acquiredProjectLock != null ) + { + acquiredProjectLock.unlock(); + } + if ( acquiredAggregatorLock != null ) + { + acquiredAggregatorLock.unlock(); + } + } + + @SuppressWarnings( { "unchecked", "rawtypes" } ) + private Lock getProjectLock( MavenSession session ) + { + SessionData data = session.getRepositorySession().getData(); + ConcurrentMap locks = ( ConcurrentMap ) data.get( ProjectLock.class ); + // initialize the value if not already done (in case of a concurrent access) to the method + if ( locks == null ) + { + // the call to data.set(k, null, v) is effectively a call to data.putIfAbsent(k, v) + data.set( ProjectLock.class, null, new ConcurrentHashMap<>() ); + locks = ( ConcurrentMap ) data.get( ProjectLock.class ); + } + Lock acquiredProjectLock = locks.get( session.getCurrentProject() ); + if ( acquiredProjectLock == null ) + { + acquiredProjectLock = new ReentrantLock(); + Lock prev = locks.putIfAbsent( session.getCurrentProject(), acquiredProjectLock ); + if ( prev != null ) + { + acquiredProjectLock = prev; + } + } + return acquiredProjectLock; + } + } + + private void doExecute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex, + DependencyContext dependencyContext ) + throws LifecycleExecutionException + { + MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor(); + List forkedProjects = executeForkedExecutions( mojoExecution, session, projectIndex ); ensureDependenciesAreResolved( mojoDescriptor, session, dependencyContext ); 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 6adb10e8f4e2..40ba60dadfeb 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 @@ -32,6 +32,7 @@ import java.util.Collections; import java.util.List; import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.maven.AbstractCoreMavenComponentTestCase; import org.apache.maven.artifact.InvalidArtifactRTException; @@ -119,6 +120,18 @@ public void testResolveDependencies() assertEquals( 1, results.size() ); MavenProject mavenProject = results.get( 0 ).getProject(); assertEquals( 1, mavenProject.getArtifacts().size() ); + + final MavenProject project = mavenProject; + final AtomicInteger artifactsResultInAnotherThead = new AtomicInteger(); + Thread t = new Thread(new Runnable() { + @Override + public void run() { + artifactsResultInAnotherThead.set(project.getArtifacts().size()); + } + }); + t.start(); + t.join(); + assertEquals( project.getArtifacts().size(), artifactsResultInAnotherThead.get() ); } public void testDontResolveDependencies() From 4ff27db4f9111fbd4268d66b8f18dd44b61df0ee Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 17 Dec 2021 08:57:42 +0100 Subject: [PATCH 07/37] [MNG-7156][MNG-7285] Fix typo in test --- .../java/org/apache/maven/project/ProjectBuilderTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 40ba60dadfeb..aae5f24baa6f 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 @@ -122,16 +122,16 @@ public void testResolveDependencies() assertEquals( 1, mavenProject.getArtifacts().size() ); final MavenProject project = mavenProject; - final AtomicInteger artifactsResultInAnotherThead = new AtomicInteger(); + final AtomicInteger artifactsResultInAnotherThread = new AtomicInteger(); Thread t = new Thread(new Runnable() { @Override public void run() { - artifactsResultInAnotherThead.set(project.getArtifacts().size()); + artifactsResultInAnotherThread.set(project.getArtifacts().size()); } }); t.start(); t.join(); - assertEquals( project.getArtifacts().size(), artifactsResultInAnotherThead.get() ); + assertEquals( project.getArtifacts().size(), artifactsResultInAnotherThread.get() ); } public void testDontResolveDependencies() From 6ae4f7e2c54113192fdd4b7efe8404088f21539f Mon Sep 17 00:00:00 2001 From: Sylwester Lachiewicz Date: Fri, 17 Dec 2021 11:01:47 +0100 Subject: [PATCH 08/37] Bump Java to 17 --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 5d5d998c0398..4d411dbbde7c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -23,7 +23,7 @@ def buildOs = 'linux' def buildJdk = '8' def buildMvn = '3.6.0' def runITsOses = ['linux', 'windows'] -def runITsJdks = ['7', '8', '11','12'] +def runITsJdks = ['7', '8', '11','17'] def runITsMvn = '3.6.0' def runITscommand = "mvn clean install -Prun-its,embedded -B -U -V" // -DmavenDistro=... -Dmaven.test.failure.ignore=true def tests From 8348d2bd0a22bf50bbbe7401ec4e848ff0f32da3 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sun, 26 Dec 2021 22:11:40 +0100 Subject: [PATCH 09/37] Fix SLF4J license link --- .../main/appended-resources/licenses/MIT-slf4j-api-1.7.32.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.32.txt b/apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.32.txt index ec8e1107be01..712cd8c141d0 100644 --- a/apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.32.txt +++ b/apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.32.txt @@ -1,4 +1,4 @@ -https://raw.githubusercontent.com/qos-ch/slf4j/v_1.7.30/LICENSE.txt +https://raw.githubusercontent.com/qos-ch/slf4j/v_1.7.32/LICENSE.txt Copyright (c) 2004-2017 QOS.ch All rights reserved. From 100b17e1d7163cd263b7ee6e372ab76b3f87dd08 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sun, 26 Dec 2021 19:55:01 +0100 Subject: [PATCH 10/37] [MNG-7370] Upgrade Maven Wagon to 3.5.1 This closes #644 --- apache-maven/pom.xml | 8 ------- .../licenses/MIT-jsoup-1.12.1.txt | 23 ------------------- apache-maven/src/main/assembly/component.xml | 1 - pom.xml | 11 +-------- 4 files changed, 1 insertion(+), 42 deletions(-) delete mode 100644 apache-maven/src/main/appended-resources/licenses/MIT-jsoup-1.12.1.txt diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml index 6e12bb0e4d4c..f8be416504c6 100644 --- a/apache-maven/pom.xml +++ b/apache-maven/pom.xml @@ -79,14 +79,6 @@ under the License. - - - org.jsoup - jsoup - runtime - org.slf4j jcl-over-slf4j diff --git a/apache-maven/src/main/appended-resources/licenses/MIT-jsoup-1.12.1.txt b/apache-maven/src/main/appended-resources/licenses/MIT-jsoup-1.12.1.txt deleted file mode 100644 index fa8a44e09e62..000000000000 --- a/apache-maven/src/main/appended-resources/licenses/MIT-jsoup-1.12.1.txt +++ /dev/null @@ -1,23 +0,0 @@ -https://raw.githubusercontent.com/jhy/jsoup/jsoup-1.12.1/LICENSE - -The MIT License - -Copyright (c) 2009-2019 Jonathan Hedley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/apache-maven/src/main/assembly/component.xml b/apache-maven/src/main/assembly/component.xml index ad16c25fb843..c3014bd06859 100644 --- a/apache-maven/src/main/assembly/component.xml +++ b/apache-maven/src/main/assembly/component.xml @@ -31,7 +31,6 @@ under the License. lib org.codehaus.plexus:plexus-classworlds - org.jsoup:jsoup diff --git a/pom.xml b/pom.xml index 5704043efefe..102419305b62 100644 --- a/pom.xml +++ b/pom.xml @@ -59,8 +59,7 @@ under the License. 3.3.0 4.2.2 0.3.5 - 3.4.3 - 1.12.1 + 3.5.1 2.0 2.0 1.11 @@ -342,14 +341,6 @@ under the License. - - - org.jsoup - jsoup - ${jsoupVersion} - org.apache.maven.resolver From e09baa8ac4fcef82baacba4a66386f7479c753d9 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Thu, 30 Dec 2021 14:52:36 +0100 Subject: [PATCH 11/37] Improve PR template --- .github/pull_request_template.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 2208cd74948c..b4a4f833345b 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,17 +1,16 @@ -Following this checklist to help us incorporate your +Following this checklist to help us incorporate your contribution quickly and easily: - - [ ] Make sure there is a [JIRA issue](https://issues.apache.org/jira/browse/MNG) filed - for the change (usually before you start working on it). Trivial changes like typos do not - require a JIRA issue. Your pull request should address just this issue, without + - [ ] Make sure there is a [JIRA issue](https://issues.apache.org/jira/browse/MNG) filed + for the change (usually before you start working on it). Trivial changes like typos do not + require a JIRA issue. Your pull request should address just this issue, without pulling in other changes. - [ ] Each commit in the pull request should have a meaningful subject line and body. - - [ ] Format the pull request title like `[MNG-XXX] - Fixes bug in ApproximateQuantiles`, - where you replace `MNG-XXX` with the appropriate JIRA issue. Best practice - is to use the JIRA issue title in the pull request title and in the first line of the - commit message. + - [ ] Format the pull request title like `[MNG-XXX] SUMMARY`, where you replace `MNG-XXX` + and `SUMMARY` with the appropriate JIRA issue. Best practice is to use the JIRA issue + title in the pull request title and in the first line of the commit message. - [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why. - - [ ] Run `mvn clean verify` to make sure basic checks pass. A more thorough check will + - [ ] Run `mvn clean verify` to make sure basic checks pass. A more thorough check will be performed on your pull request automatically. - [ ] You have run the [Core IT][core-its] successfully. @@ -19,7 +18,7 @@ If your pull request is about ~20 lines of code you don't need to sign an [Individual Contributor License Agreement](https://www.apache.org/licenses/icla.pdf) if you are unsure please ask on the developers list. -To make clear that you license your contribution under +To make clear that you license your contribution under the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/LICENSE-2.0) you have to acknowledge this by using the following check-box. From d173bf9cc5e6a4f550a9b50f99eca3561b1ca40e Mon Sep 17 00:00:00 2001 From: Jeff Hodges Date: Wed, 29 Dec 2021 01:19:03 -0800 Subject: [PATCH 12/37] [MNG-7377] Add .vscode/ to .gitignore VS Code creates directories with configurations in project directories. This is usually fine, but triggers the `apache-rat` license alarms and future VS Code users might accidentally commit the directory. To solve the alarm and avoid future issues, we add it to .gitignore. This closes #646 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f85dc5684299..28aa49bdc335 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ out/ .java-version .factorypath .checkstyle +.vscode/ From ef74a62451684c8c60cc9db4b6720c8edb89a165 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sat, 25 Dec 2021 12:28:18 +0100 Subject: [PATCH 13/37] [MNG-7374] Mutating RelocatedArtifact does not retain type This closes #641 --- .../internal/RelocatedArtifact.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java index 2e277f0e4c1d..4614ccfe5c5c 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java @@ -86,6 +86,40 @@ public String getVersion() } } + // Revise these three methods when MRESOLVER-233 is delivered + @Override + public Artifact setVersion( String version ) + { + String current = getVersion(); + if ( current.equals( version ) || ( version == null && current.length() <= 0 ) ) + { + return this; + } + return new RelocatedArtifact( artifact, groupId, artifactId, version ); + } + + @Override + public Artifact setFile( File file ) + { + File current = getFile(); + if ( Objects.equals( current, file ) ) + { + return this; + } + return new RelocatedArtifact( artifact.setFile( file ), groupId, artifactId, version ); + } + + @Override + public Artifact setProperties( Map properties ) + { + Map current = getProperties(); + if ( current.equals( properties ) || ( properties == null && current.isEmpty() ) ) + { + return this; + } + return new RelocatedArtifact( artifact.setProperties( properties ), groupId, artifactId, version ); + } + public String getClassifier() { return artifact.getClassifier(); From 05b748ff6aa15aa63a9c9d5f9f5679f47bf9e83d Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sat, 25 Dec 2021 12:28:47 +0100 Subject: [PATCH 14/37] [MNG-5561] Plugin relocation loses configuration Previously, to locate plugin configuration in the project the plugin descriptor was read and the GA were extracted. This always worked because the GA from the model and the GA from plugin descriptor (plugin.xml) were identical. When a plugin is relocated the target artifact is read, thus its plugin descriptor as well. Naturally, the GA of new (relocated) does not correspond to the old (static) one in the model. Therefore, the configuration is not found. New approach is to use the original plugin GA to locate the configuration in the model regardless of relocation. --- .../internal/DefaultMojoExecutionConfigurator.java | 4 ++-- .../lifecycle/internal/stub/BuildPluginManagerStub.java | 2 +- .../maven/lifecycle/internal/stub/MojoExecutorStub.java | 9 ++++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java index 176ba320a71a..8c809de82de3 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java @@ -41,9 +41,9 @@ public class DefaultMojoExecutionConfigurator @Override public void configure( MavenProject project, MojoExecution mojoExecution, boolean allowPluginLevelConfig ) { - String g = mojoExecution.getGroupId(); + String g = mojoExecution.getPlugin().getGroupId(); - String a = mojoExecution.getArtifactId(); + String a = mojoExecution.getPlugin().getArtifactId(); Plugin plugin = findPlugin( g, a, project.getBuildPlugins() ); diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java index 133bcb3a2137..cdb00fc02adf 100644 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java +++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java @@ -42,7 +42,7 @@ public PluginDescriptor loadPlugin( Plugin plugin, List reposi public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List repositories, RepositorySystemSession session ) { - return MojoExecutorStub.createMojoDescriptor( plugin.getKey() ); + return MojoExecutorStub.createMojoDescriptor( plugin ); } public ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor ) diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java index 8a6580b699af..763893e6ce9a 100644 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java +++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java @@ -21,6 +21,7 @@ import org.apache.maven.lifecycle.internal.MojoExecutor; import org.apache.maven.lifecycle.internal.PhaseRecorder; import org.apache.maven.lifecycle.internal.ProjectIndex; +import org.apache.maven.model.Plugin; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; @@ -54,12 +55,14 @@ public void execute( MavenSession session, List mojoExecutions, P } - public static MojoDescriptor createMojoDescriptor( String mojoDescription ) + public static MojoDescriptor createMojoDescriptor( Plugin plugin ) { final PluginDescriptor descriptor = new PluginDescriptor(); - descriptor.setArtifactId( mojoDescription ); + descriptor.setGroupId( plugin.getGroupId() ); + descriptor.setArtifactId( plugin.getArtifactId() ); + descriptor.setPlugin( plugin ); + descriptor.setVersion( plugin.getVersion() ); final MojoDescriptor mojoDescriptor = new MojoDescriptor(); - mojoDescriptor.setDescription( mojoDescription ); mojoDescriptor.setPluginDescriptor( descriptor ); return mojoDescriptor; } From 0f3c39b8ed1a875ec58ebe91b2b18ca8b64b2fd3 Mon Sep 17 00:00:00 2001 From: Ravil Galeyev Date: Sat, 15 May 2021 13:51:15 +0200 Subject: [PATCH 15/37] [MNG-6802] FileProfileActivator changes FileProfileActivator.exists which lets flattened resolveCiFriendliesOnly depending fail activating profile Cherry picked from 3fabb639a31d6076b1649c1a08828febabddf44a This closes #649 --- .../model/building/DefaultModelBuilder.java | 66 ++++++++- .../building/DefaultModelBuilderFactory.java | 10 +- ...ProfileActivationFilePathInterpolator.java | 103 ++++++++++++++ .../activation/FileProfileActivator.java | 66 ++------- .../DefaultModelBuilderFactoryTest.java | 36 ++++- .../activation/FileProfileActivatorTest.java | 131 ++++++++++++++++++ 6 files changed, 354 insertions(+), 58 deletions(-) create mode 100644 maven-model-builder/src/main/java/org/apache/maven/model/path/ProfileActivationFilePathInterpolator.java create mode 100644 maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/FileProfileActivatorTest.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 70c9ed529cd2..94de1d18e5a1 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 @@ -24,6 +24,7 @@ import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; import org.apache.maven.artifact.versioning.VersionRange; import org.apache.maven.model.Activation; +import org.apache.maven.model.ActivationFile; import org.apache.maven.model.Build; import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; @@ -46,11 +47,13 @@ import org.apache.maven.model.normalization.ModelNormalizer; import org.apache.maven.model.path.ModelPathTranslator; import org.apache.maven.model.path.ModelUrlNormalizer; +import org.apache.maven.model.path.ProfileActivationFilePathInterpolator; import org.apache.maven.model.plugin.LifecycleBindingsInjector; import org.apache.maven.model.plugin.PluginConfigurationExpander; import org.apache.maven.model.plugin.ReportConfigurationExpander; import org.apache.maven.model.plugin.ReportingConverter; import org.apache.maven.model.profile.DefaultProfileActivationContext; +import org.apache.maven.model.profile.ProfileActivationContext; import org.apache.maven.model.profile.ProfileInjector; import org.apache.maven.model.profile.ProfileSelector; import org.apache.maven.model.resolution.InvalidRepositoryException; @@ -59,8 +62,10 @@ import org.apache.maven.model.resolution.WorkspaceModelResolver; import org.apache.maven.model.superpom.SuperPomProvider; import org.apache.maven.model.validation.ModelValidator; +import org.codehaus.plexus.interpolation.InterpolationException; import org.codehaus.plexus.interpolation.MapBasedValueSource; import org.codehaus.plexus.interpolation.StringSearchInterpolator; +import org.codehaus.plexus.util.StringUtils; import org.eclipse.sisu.Nullable; import java.io.File; @@ -142,6 +147,9 @@ public class DefaultModelBuilder @Inject private ReportingConverter reportingConverter; + @Inject + private ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; + public DefaultModelBuilder setModelProcessor( ModelProcessor modelProcessor ) { this.modelProcessor = modelProcessor; @@ -244,6 +252,13 @@ public DefaultModelBuilder setReportingConverter( ReportingConverter reportingCo return this; } + public DefaultModelBuilder setProfileActivationFilePathInterpolator( + ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator ) + { + this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator; + return this; + } + @SuppressWarnings( "checkstyle:methodlength" ) @Override public ModelBuildingResult build( ModelBuildingRequest request ) @@ -317,7 +332,9 @@ protected ModelBuildingResult build( ModelBuildingRequest request, Collection interpolatedActivations = getProfileActivations( rawModel, false ); + Map interpolatedActivations = getInterpolatedActivations( rawModel, + profileActivationContext, + problems ); injectProfileActivations( tmpModel, interpolatedActivations ); // profile injection @@ -440,6 +457,51 @@ else if ( !parentIds.add( parentData.getId() ) ) return result; } + private Map getInterpolatedActivations( Model rawModel, + DefaultProfileActivationContext context, + DefaultModelProblemCollector problems ) + { + Map interpolatedActivations = getProfileActivations( rawModel, true ); + for ( Activation activation : interpolatedActivations.values() ) + { + if ( activation.getFile() != null ) + { + replaceWithInterpolatedValue( activation.getFile(), context, problems ); + } + } + return interpolatedActivations; + } + + private void replaceWithInterpolatedValue( ActivationFile activationFile, ProfileActivationContext context, + DefaultModelProblemCollector problems ) + { + try + { + if ( StringUtils.isNotEmpty( activationFile.getExists() ) ) + { + String path = activationFile.getExists(); + String absolutePath = profileActivationFilePathInterpolator.interpolate( path, context ); + activationFile.setExists( absolutePath ); + } + else if ( StringUtils.isNotEmpty( activationFile.getMissing() ) ) + { + String path = activationFile.getMissing(); + String absolutePath = profileActivationFilePathInterpolator.interpolate( path, context ); + activationFile.setMissing( absolutePath ); + } + } + catch ( InterpolationException e ) + { + String path = StringUtils.isNotEmpty( + activationFile.getExists() ) ? activationFile.getExists() : activationFile.getMissing(); + + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( + "Failed to interpolate file location " + path + ": " + e.getMessage() ).setLocation( + activationFile.getLocation( StringUtils.isNotEmpty( activationFile.getExists() ) ? "exists" : "missing" ) ) + .setException( e ) ); + } + } + @Override public ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result ) throws ModelBuildingException @@ -818,7 +880,7 @@ private Model interpolateModel( Model model, ModelBuildingRequest request, Model problems.add( mpcr ); } - + } interpolatedModel.setPomFile( model.getPomFile() ); diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java index 4240574ff214..730c5a29fee7 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java @@ -43,6 +43,7 @@ import org.apache.maven.model.path.ModelPathTranslator; import org.apache.maven.model.path.ModelUrlNormalizer; import org.apache.maven.model.path.PathTranslator; +import org.apache.maven.model.path.ProfileActivationFilePathInterpolator; import org.apache.maven.model.path.UrlNormalizer; import org.apache.maven.model.plugin.DefaultPluginConfigurationExpander; import org.apache.maven.model.plugin.DefaultReportConfigurationExpander; @@ -109,7 +110,13 @@ protected ProfileSelector newProfileSelector() protected ProfileActivator[] newProfileActivators() { return new ProfileActivator[] { new JdkVersionProfileActivator(), new OperatingSystemProfileActivator(), - new PropertyProfileActivator(), new FileProfileActivator().setPathTranslator( newPathTranslator() ) }; + new PropertyProfileActivator(), new FileProfileActivator() + .setProfileActivationFilePathInterpolator( newProfileActivationFilePathInterpolator() ) }; + } + + protected ProfileActivationFilePathInterpolator newProfileActivationFilePathInterpolator() + { + return new ProfileActivationFilePathInterpolator().setPathTranslator( newPathTranslator() ); } protected UrlNormalizer newUrlNormalizer() @@ -225,6 +232,7 @@ public DefaultModelBuilder newInstance() modelBuilder.setPluginConfigurationExpander( newPluginConfigurationExpander() ); modelBuilder.setReportConfigurationExpander( newReportConfigurationExpander() ); modelBuilder.setReportingConverter( newReportingConverter() ); + modelBuilder.setProfileActivationFilePathInterpolator( newProfileActivationFilePathInterpolator() ); return modelBuilder; } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/ProfileActivationFilePathInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/ProfileActivationFilePathInterpolator.java new file mode 100644 index 000000000000..c2f815b7f7ba --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/ProfileActivationFilePathInterpolator.java @@ -0,0 +1,103 @@ +package org.apache.maven.model.path; + +/* + * 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.ActivationFile; +import org.apache.maven.model.profile.ProfileActivationContext; +import org.codehaus.plexus.interpolation.AbstractValueSource; +import org.codehaus.plexus.interpolation.InterpolationException; +import org.codehaus.plexus.interpolation.MapBasedValueSource; +import org.codehaus.plexus.interpolation.RegexBasedInterpolator; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import java.io.File; + +/** + * Finds an absolute path for {@link ActivationFile#getExists()} or {@link ActivationFile#getMissing()} + * + * @author Ravil Galeyev + */ +@Named +@Singleton +public class ProfileActivationFilePathInterpolator +{ + + @Inject + private PathTranslator pathTranslator; + + public ProfileActivationFilePathInterpolator setPathTranslator( PathTranslator pathTranslator ) + { + this.pathTranslator = pathTranslator; + return this; + } + + /** + * Interpolates given {@code path}. + * + * @return absolute path or {@code null} if the input was {@code null} + */ + public String interpolate( String path, ProfileActivationContext context ) throws InterpolationException + { + if ( path == null ) + { + return null; + } + + RegexBasedInterpolator interpolator = new RegexBasedInterpolator(); + + final File basedir = context.getProjectDirectory(); + + if ( basedir != null ) + { + interpolator.addValueSource( new AbstractValueSource( false ) + { + @Override + public Object getValue( String expression ) + { + /* + * We intentionally only support ${basedir} and not ${project.basedir} as the latter form + * would suggest that other project.* expressions can be used which is beyond the design. + */ + if ( "basedir".equals( expression ) ) + { + return basedir.getAbsolutePath(); + } + return null; + } + } ); + } + else if ( path.contains( "${basedir}" ) ) + { + return null; + } + + interpolator.addValueSource( new MapBasedValueSource( context.getProjectProperties() ) ); + + interpolator.addValueSource( new MapBasedValueSource( context.getUserProperties() ) ); + + interpolator.addValueSource( new MapBasedValueSource( context.getSystemProperties() ) ); + + String absolutePath = interpolator.interpolate( path, "" ); + + return pathTranslator.alignToBaseDirectory( absolutePath, basedir ); + } +} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/FileProfileActivator.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/FileProfileActivator.java index abfa57edfc03..923ffd2eb3cf 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/FileProfileActivator.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/FileProfileActivator.java @@ -28,15 +28,13 @@ import org.apache.maven.model.Activation; import org.apache.maven.model.ActivationFile; import org.apache.maven.model.Profile; -import org.apache.maven.model.building.ModelProblemCollector; import org.apache.maven.model.building.ModelProblem.Severity; import org.apache.maven.model.building.ModelProblem.Version; +import org.apache.maven.model.building.ModelProblemCollector; import org.apache.maven.model.building.ModelProblemCollectorRequest; -import org.apache.maven.model.path.PathTranslator; +import org.apache.maven.model.path.ProfileActivationFilePathInterpolator; import org.apache.maven.model.profile.ProfileActivationContext; -import org.codehaus.plexus.interpolation.AbstractValueSource; -import org.codehaus.plexus.interpolation.MapBasedValueSource; -import org.codehaus.plexus.interpolation.RegexBasedInterpolator; +import org.codehaus.plexus.interpolation.InterpolationException; import org.codehaus.plexus.util.StringUtils; /** @@ -58,11 +56,12 @@ public class FileProfileActivator { @Inject - private PathTranslator pathTranslator; + private ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator; - public FileProfileActivator setPathTranslator( PathTranslator pathTranslator ) + public FileProfileActivator setProfileActivationFilePathInterpolator( + ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator ) { - this.pathTranslator = pathTranslator; + this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator; return this; } @@ -101,64 +100,23 @@ else if ( StringUtils.isNotEmpty( file.getMissing() ) ) return false; } - RegexBasedInterpolator interpolator = new RegexBasedInterpolator(); - - final File basedir = context.getProjectDirectory(); - - if ( basedir != null ) - { - interpolator.addValueSource( new AbstractValueSource( false ) - { - @Override - public Object getValue( String expression ) - { - /* - * NOTE: We intentionally only support ${basedir} and not ${project.basedir} as the latter form - * would suggest that other project.* expressions can be used which is however beyond the design. - */ - if ( "basedir".equals( expression ) ) - { - return basedir.getAbsolutePath(); - } - return null; - } - } ); - } - else if ( path.contains( "${basedir}" ) ) - { - return false; - } - - interpolator.addValueSource( new MapBasedValueSource( context.getProjectProperties() ) ); - - interpolator.addValueSource( new MapBasedValueSource( context.getUserProperties() ) ); - - interpolator.addValueSource( new MapBasedValueSource( context.getSystemProperties() ) ); - try { - path = interpolator.interpolate( path, "" ); + path = profileActivationFilePathInterpolator.interpolate( path, context ); } - catch ( Exception e ) + catch ( InterpolationException e ) { problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) .setMessage( "Failed to interpolate file location " + path + " for profile " + profile.getId() - + ": " + e.getMessage() ) + + ": " + e.getMessage() ) .setLocation( file.getLocation( missing ? "missing" : "exists" ) ) .setException( e ) ); return false; } - path = pathTranslator.alignToBaseDirectory( path, basedir ); - - // replace activation value with interpolated value - if ( missing ) + if ( path == null ) { - file.setMissing( path ); - } - else - { - file.setExists( path ); + return false; } File f = new File( path ); diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderFactoryTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderFactoryTest.java index 90b65a4c921a..32c7d268d5cf 100644 --- a/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderFactoryTest.java +++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderFactoryTest.java @@ -20,11 +20,17 @@ */ import java.io.File; +import java.io.FileInputStream; +import java.nio.file.Paths; +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.codehaus.plexus.util.xml.Xpp3Dom; import junit.framework.TestCase; +import org.junit.Test; + /** * @author Benjamin Bentmann */ @@ -32,9 +38,11 @@ public class DefaultModelBuilderFactoryTest extends TestCase { + private static final String BASE_DIR = Paths.get( "src", "test", "resources", "poms", "factory" ).toString(); + private File getPom( String name ) { - return new File( "src/test/resources/poms/factory/" + name + ".xml" ).getAbsoluteFile(); + return new File( Paths.get( BASE_DIR, name + ".xml" ).toString() ).getAbsoluteFile(); } public void testCompleteWiring() @@ -56,4 +64,30 @@ public void testCompleteWiring() assertEquals( " 1.5 ", conf.getChild( "target" ).getValue() ); } + @Test + public void testPomChanges() throws Exception + { + ModelBuilder builder = new DefaultModelBuilderFactory().newInstance(); + assertNotNull( builder ); + File pom = getPom( "simple" ); + + String originalExists = readPom( pom ).getProfiles().get( 1 ).getActivation().getFile().getExists(); + + DefaultModelBuildingRequest request = new DefaultModelBuildingRequest(); + request.setProcessPlugins( true ); + request.setPomFile( pom ); + ModelBuildingResult result = builder.build( request ); + String resultExists = result.getRawModel().getProfiles().get( 1 ).getActivation().getFile().getExists(); + + assertEquals( originalExists, resultExists ); + assertTrue( result.getEffectiveModel().getProfiles().get( 1 ).getActivation().getFile().getExists() + .contains( BASE_DIR ) ); + } + + private static Model readPom( File file ) throws Exception + { + MavenXpp3Reader reader = new MavenXpp3Reader(); + + return reader.read( new FileInputStream( file ) ); + } } diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/FileProfileActivatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/FileProfileActivatorTest.java new file mode 100644 index 000000000000..c8b5c93b8d17 --- /dev/null +++ b/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/FileProfileActivatorTest.java @@ -0,0 +1,131 @@ +package org.apache.maven.model.profile.activation; + +/* + * 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.Activation; +import org.apache.maven.model.ActivationFile; +import org.apache.maven.model.Profile; +import org.apache.maven.model.path.DefaultPathTranslator; +import org.apache.maven.model.path.ProfileActivationFilePathInterpolator; +import org.apache.maven.model.profile.DefaultProfileActivationContext; + +import org.junit.Before; +import org.junit.Test; + +import java.nio.file.Files; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +/** + * Tests {@link FileProfileActivator}. + * + * @author Ravil Galeyev + */ +public class FileProfileActivatorTest extends AbstractProfileActivatorTest +{ + Path tempDir; + + private final DefaultProfileActivationContext context = new DefaultProfileActivationContext(); + + public FileProfileActivatorTest() + { + super( FileProfileActivator.class ); + } + + @Before + public void setUp() throws Exception + { + super.setUp(); + + tempDir = Files.createTempDirectory( null ); + + activator.setProfileActivationFilePathInterpolator( + new ProfileActivationFilePathInterpolator().setPathTranslator( new DefaultPathTranslator() ) ); + + context.setProjectDirectory( new File( tempDir.toString() ) ); + + File file = new File( tempDir.resolve( "file.txt" ).toString() ); + if ( !file.createNewFile() ) + { + throw new IOException( "Can't create " + file ); + } + } + + @Test + public void testIsActiveNoFile() + { + assertActivation( false, newExistsProfile( null ), context ); + assertActivation( false, newExistsProfile( "someFile.txt" ), context ); + assertActivation( false, newExistsProfile( "${basedir}/someFile.txt" ), context ); + + assertActivation( false, newMissingProfile( null ), context ); + assertActivation( true, newMissingProfile( "someFile.txt" ), context ); + assertActivation( true, newMissingProfile( "${basedir}/someFile.txt" ), context ); + } + + @Test + public void testIsActiveExistsFileExists() + { + assertActivation( true, newExistsProfile( "file.txt" ), context ); + assertActivation( true, newExistsProfile( "${basedir}" ), context ); + assertActivation( true, newExistsProfile( "${basedir}/" + "file.txt" ), context ); + + assertActivation( false, newMissingProfile( "file.txt" ), context ); + assertActivation( false, newMissingProfile( "${basedir}" ), context ); + assertActivation( false, newMissingProfile( "${basedir}/" + "file.txt" ), context ); + } + + @Test + public void testIsActiveExistsLeavesFileUnchanged() + { + Profile profile = newExistsProfile( "file.txt" ); + assertEquals( "file.txt", profile.getActivation().getFile().getExists() ); + + assertActivation( true, profile, context ); + + assertEquals( "file.txt", profile.getActivation().getFile().getExists() ); + } + + private Profile newExistsProfile( String filePath ) + { + ActivationFile activationFile = new ActivationFile(); + activationFile.setExists( filePath ); + return newProfile( activationFile ); + } + + private Profile newMissingProfile( String filePath ) + { + ActivationFile activationFile = new ActivationFile(); + activationFile.setMissing( filePath ); + return newProfile( activationFile ); + } + + private Profile newProfile( ActivationFile activationFile ) + { + Activation activation = new Activation(); + activation.setFile( activationFile ); + + Profile profile = new Profile(); + profile.setActivation( activation ); + + return profile; + } +} From f4fd031828c3cd6a6b8184d4ee0e914cd86009a0 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Thu, 6 Jan 2022 22:26:58 +0100 Subject: [PATCH 16/37] Fix checkstyle issue --- .../org/apache/maven/model/building/DefaultModelBuilder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 94de1d18e5a1..813b76297fe6 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 @@ -497,7 +497,8 @@ else if ( StringUtils.isNotEmpty( activationFile.getMissing() ) ) problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( "Failed to interpolate file location " + path + ": " + e.getMessage() ).setLocation( - activationFile.getLocation( StringUtils.isNotEmpty( activationFile.getExists() ) ? "exists" : "missing" ) ) + activationFile.getLocation( StringUtils.isNotEmpty( activationFile.getExists() ) + ? "exists" : "missing" ) ) .setException( e ) ); } } From 8456294977b40660ce37db853de344f0d26ee46d Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 7 Jan 2022 09:51:21 +0100 Subject: [PATCH 17/37] [MNG-6326] Make the build fail if core extensions can not be loaded (#648) --- .../java/org/apache/maven/cli/MavenCli.java | 86 ++++++++----------- .../BootstrapCoreExtensionManager.java | 37 +++++--- .../ExtensionResolutionException.java | 47 ++++++++++ .../src/main/mdo/core-extensions.mdo | 26 ++++++ 4 files changed, 134 insertions(+), 62 deletions(-) create mode 100644 maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java index fbcb05f91371..ed695ebbf20c 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java @@ -705,6 +705,7 @@ protected void configure() private List loadCoreExtensions( CliRequest cliRequest, ClassRealm containerRealm, Set providedArtifacts ) + throws Exception { if ( cliRequest.multiModuleProjectDirectory == null ) { @@ -717,75 +718,62 @@ private List loadCoreExtensions( CliRequest cliRequest, Clas return Collections.emptyList(); } - try + List extensions = readCoreExtensionsDescriptor( extensionsFile ); + if ( extensions.isEmpty() ) { - List extensions = readCoreExtensionsDescriptor( extensionsFile ); - if ( extensions.isEmpty() ) - { - return Collections.emptyList(); - } + return Collections.emptyList(); + } - ContainerConfiguration cc = new DefaultContainerConfiguration() // - .setClassWorld( cliRequest.classWorld ) // - .setRealm( containerRealm ) // - .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) // - .setAutoWiring( true ) // - .setJSR250Lifecycle( true ) // - .setName( "maven" ); + ContainerConfiguration cc = new DefaultContainerConfiguration() // + .setClassWorld( cliRequest.classWorld ) // + .setRealm( containerRealm ) // + .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) // + .setAutoWiring( true ) // + .setJSR250Lifecycle( true ) // + .setName( "maven" ); - DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule() + DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule() + { + @Override + protected void configure() { - @Override - protected void configure() - { - bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory ); - } - } ); + bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory ); + } + } ); - try - { - container.setLookupRealm( null ); + try + { + container.setLookupRealm( null ); - container.setLoggerManager( plexusLoggerManager ); + container.setLoggerManager( plexusLoggerManager ); - container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() ); + container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() ); - Thread.currentThread().setContextClassLoader( container.getContainerRealm() ); + Thread.currentThread().setContextClassLoader( container.getContainerRealm() ); - executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class ); + executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class ); - configurationProcessors = container.lookupMap( ConfigurationProcessor.class ); + configurationProcessors = container.lookupMap( ConfigurationProcessor.class ); - configure( cliRequest ); + configure( cliRequest ); - MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request ); + MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request ); - request = populateRequest( cliRequest, request ); + request = populateRequest( cliRequest, request ); - request = executionRequestPopulator.populateDefaults( request ); + request = executionRequestPopulator.populateDefaults( request ); - BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class ); + BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class ); - return Collections.unmodifiableList( resolver.loadCoreExtensions( request, providedArtifacts, - extensions ) ); + return Collections.unmodifiableList( resolver.loadCoreExtensions( request, providedArtifacts, + extensions ) ); - } - finally - { - executionRequestPopulator = null; - container.dispose(); - } - } - catch ( RuntimeException e ) - { - // runtime exceptions are most likely bugs in maven, let them bubble up to the user - throw e; } - catch ( Exception e ) + finally { - slf4jLogger.warn( "Failed to read extensions descriptor {}: {}", extensionsFile, e.getMessage() ); + executionRequestPopulator = null; + container.dispose(); } - return Collections.emptyList(); } private List readCoreExtensionsDescriptor( File extensionsFile ) diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java index 9fada05db83b..a47326977d0e 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java @@ -128,19 +128,30 @@ private CoreExtensionEntry createExtension( CoreExtension extension, List resolveExtension( CoreExtension extension, RepositorySystemSession repoSession, List repositories, DependencyFilter dependencyFilter ) - throws PluginResolutionException + throws ExtensionResolutionException { - Plugin plugin = new Plugin(); - plugin.setGroupId( extension.getGroupId() ); - plugin.setArtifactId( extension.getArtifactId() ); - plugin.setVersion( extension.getVersion() ); - - DependencyNode root = - pluginDependenciesResolver.resolveCoreExtension( plugin, dependencyFilter, repositories, repoSession ); - PreorderNodeListGenerator nlg = new PreorderNodeListGenerator(); - root.accept( nlg ); - List artifacts = nlg.getArtifacts( false ); - - return artifacts; + try + { + // TODO: enhance the PluginDependenciesResolver to provide a + // TODO: resolveCoreExtension method which uses a CoreExtension + // TODO: object instead of a Plugin as this makes no sense + Plugin plugin = new Plugin(); + plugin.setGroupId( extension.getGroupId() ); + plugin.setArtifactId( extension.getArtifactId() ); + plugin.setVersion( extension.getVersion() ); + + DependencyNode root = pluginDependenciesResolver + .resolveCoreExtension( plugin, dependencyFilter, repositories, repoSession ); + PreorderNodeListGenerator nlg = new PreorderNodeListGenerator(); + root.accept( nlg ); + List artifacts = nlg.getArtifacts( false ); + + return artifacts; + } + catch ( PluginResolutionException e ) + { + throw new ExtensionResolutionException( extension, e.getCause() ); + } } + } diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java b/maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java new file mode 100644 index 000000000000..4f8cff9cb346 --- /dev/null +++ b/maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java @@ -0,0 +1,47 @@ +package org.apache.maven.cli.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.cli.internal.extension.model.CoreExtension; + +/** + * Exception occurring trying to resolve a plugin. + * + * @author Brett Porter + */ +public class ExtensionResolutionException + extends Exception +{ + + private final CoreExtension extension; + + public ExtensionResolutionException( CoreExtension extension, Throwable cause ) + { + super( "Extension " + extension.getId() + " or one of its dependencies could not be resolved: " + + cause.getMessage(), cause ); + this.extension = extension; + } + + public CoreExtension getExtension() + { + return extension; + } + +} diff --git a/maven-embedder/src/main/mdo/core-extensions.mdo b/maven-embedder/src/main/mdo/core-extensions.mdo index e523d5abf325..8a74aabb5856 100644 --- a/maven-embedder/src/main/mdo/core-extensions.mdo +++ b/maven-embedder/src/main/mdo/core-extensions.mdo @@ -83,6 +83,32 @@ String + + + 1.0.0+ + + ::}, never {@code null}. + */ + public String getId() + { + StringBuilder id = new StringBuilder( 128 ); + + id.append( ( getGroupId() == null ) ? "[unknown-group-id]" : getGroupId() ); + id.append( ":" ); + id.append( ( getArtifactId() == null ) ? "[unknown-artifact-id]" : getArtifactId() ); + id.append( ":" ); + id.append( ( getVersion() == null ) ? "[unknown-version]" : getVersion() ); + + return id.toString(); + } + ]]> + + + From b4518b5fe416a552a59e5201b4569a9bc0af3153 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 10 Jan 2022 08:19:41 +0100 Subject: [PATCH 18/37] [MNG-7347] SessionScoped beans should be singletons for a given session (#653) --- .../internal/LifecycleModuleBuilder.java | 13 +- .../lifecycle/internal/LifecycleStarter.java | 3 +- .../lifecycle/internal/ReactorContext.java | 14 +- .../session/scope/internal/SessionScope.java | 159 +++++++++--------- .../scope/internal/SessionScopeTest.java | 132 +++++++++++++++ 5 files changed, 226 insertions(+), 95 deletions(-) create mode 100644 maven-core/src/test/java/org/apache/maven/session/scope/internal/SessionScopeTest.java diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java index 548fe6c8ffd6..1cbaf5334606 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java @@ -90,8 +90,12 @@ public void buildProject( MavenSession session, MavenSession rootSession, Reacto // session may be different from rootSession seeded in DefaultMaven // explicitly seed the right session here to make sure it is used by Guice - sessionScope.enter( reactorContext.getSessionScopeMemento() ); - sessionScope.seed( MavenSession.class, session ); + final boolean scoped = session != rootSession; + if ( scoped ) + { + sessionScope.enter(); + sessionScope.seed( MavenSession.class, session ); + } try { @@ -145,7 +149,10 @@ public void buildProject( MavenSession session, MavenSession rootSession, Reacto } finally { - sessionScope.exit(); + if ( scoped ) + { + sessionScope.exit(); + } session.setCurrentProject( null ); diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java index cee80739234d..834498126080 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java @@ -107,8 +107,7 @@ public void execute( MavenSession session ) ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader(); ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus( session.getProjectDependencyGraph() ); reactorContext = - new ReactorContext( result, projectIndex, oldContextClassLoader, reactorBuildStatus, - sessionScope.memento() ); + new ReactorContext( result, projectIndex, oldContextClassLoader, reactorBuildStatus ); String builderId = session.getRequest().getBuilderId(); Builder builder = builders.get( builderId ); diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java index 7df531404520..076c6229f8ef 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java @@ -20,7 +20,6 @@ */ import org.apache.maven.execution.MavenExecutionResult; -import org.apache.maven.session.scope.internal.SessionScope; /** * Context that is fixed for the entire reactor build. @@ -40,17 +39,13 @@ public class ReactorContext private final ReactorBuildStatus reactorBuildStatus; - private final SessionScope.Memento sessionScope; - public ReactorContext( MavenExecutionResult result, ProjectIndex projectIndex, - ClassLoader originalContextClassLoader, ReactorBuildStatus reactorBuildStatus, - SessionScope.Memento sessionScope ) + ClassLoader originalContextClassLoader, ReactorBuildStatus reactorBuildStatus ) { this.result = result; this.projectIndex = projectIndex; this.originalContextClassLoader = originalContextClassLoader; this.reactorBuildStatus = reactorBuildStatus; - this.sessionScope = sessionScope; } public ReactorBuildStatus getReactorBuildStatus() @@ -73,11 +68,4 @@ public ClassLoader getOriginalContextClassLoader() return originalContextClassLoader; } - /** - * @since 3.3.0 - */ - public SessionScope.Memento getSessionScopeMemento() - { - return sessionScope; - } } diff --git a/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java b/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java index ac423bc6c92c..41187fd80cbb 100644 --- a/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java +++ b/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java @@ -19,16 +19,16 @@ * under the License. */ -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; import com.google.inject.Key; import com.google.inject.OutOfScopeException; import com.google.inject.Provider; import com.google.inject.Scope; -import com.google.inject.util.Providers; /** * SessionScope @@ -36,18 +36,6 @@ public class SessionScope implements Scope { - /** - * @since 3.3.0 - */ - public static class Memento - { - final Map, Provider> seeded; - - Memento( final Map, Provider> seeded ) - { - this.seeded = Collections.unmodifiableMap( new HashMap<>( seeded ) ); - } - } private static final Provider SEEDED_KEY_PROVIDER = new Provider() { @@ -60,110 +48,127 @@ public Object get() /** * ScopeState */ - private static final class ScopeState + protected static final class ScopeState { - private final Map, Provider> seeded = new HashMap<>(); + private final ConcurrentMap, CachingProvider> provided = new ConcurrentHashMap<>(); - private final Map, Object> provided = new HashMap<>(); - } + public void seed( Class clazz, Provider value ) + { + provided.put( Key.get( clazz ), new CachingProvider<>( value ) ); + } - private final ThreadLocal> values = new ThreadLocal<>(); + @SuppressWarnings( "unchecked" ) + public Provider scope( Key key, final Provider unscoped ) + { + Provider provider = provided.get( key ); + if ( provider == null ) + { + CachingProvider newValue = new CachingProvider<>( unscoped ); + provider = provided.putIfAbsent( key, newValue ); + if ( provider == null ) + { + provider = newValue; + } + } + return ( Provider ) provider; + } - public void enter() - { - LinkedList stack = values.get(); - if ( stack == null ) + public Collection> providers() { - stack = new LinkedList<>(); - values.set( stack ); + return provided.values(); } - stack.addFirst( new ScopeState() ); + } - /** - * @since 3.3.0 - */ - public void enter( Memento memento ) + private final List values = new CopyOnWriteArrayList<>(); + + public void enter() { - enter(); - getScopeState().seeded.putAll( memento.seeded ); + values.add( 0, new ScopeState() ); } - private ScopeState getScopeState() + protected ScopeState getScopeState() { - LinkedList stack = values.get(); - if ( stack == null || stack.isEmpty() ) + if ( values.isEmpty() ) { - throw new IllegalStateException(); + throw new OutOfScopeException( "Cannot access session scope outside of a scoping block" ); } - return stack.getFirst(); + return values.get( 0 ); } public void exit() { - final LinkedList stack = values.get(); - if ( stack == null || stack.isEmpty() ) + if ( values.isEmpty() ) { throw new IllegalStateException(); } - stack.removeFirst(); - if ( stack.isEmpty() ) - { - values.remove(); - } - } - - /** - * @since 3.3.0 - */ - public Memento memento() - { - LinkedList stack = values.get(); - return new Memento( stack != null ? stack.getFirst().seeded : Collections., Provider>emptyMap() ); + values.remove( 0 ); } public void seed( Class clazz, Provider value ) { - getScopeState().seeded.put( Key.get( clazz ), value ); + getScopeState().seed( clazz, value ); } public void seed( Class clazz, final T value ) { - getScopeState().seeded.put( Key.get( clazz ), Providers.of( value ) ); + seed( clazz, new Provider() + { + @Override + public T get() + { + return value; + } + } ); } public Provider scope( final Key key, final Provider unscoped ) { + // Lazy evaluating provider return new Provider() { - @SuppressWarnings( "unchecked" ) + @Override public T get() { - LinkedList stack = values.get(); - if ( stack == null || stack.isEmpty() ) - { - throw new OutOfScopeException( "Cannot access " + key + " outside of a scoping block" ); - } + return getScopeState().scope( key, unscoped ).get(); + } + }; + } - ScopeState state = stack.getFirst(); + /** + * CachingProvider + * @param + */ + protected static class CachingProvider implements Provider + { + private final Provider provider; + private volatile T value; - Provider seeded = state.seeded.get( key ); + CachingProvider( Provider provider ) + { + this.provider = provider; + } - if ( seeded != null ) - { - return (T) seeded.get(); - } + public T value() + { + return value; + } - T provided = (T) state.provided.get( key ); - if ( provided == null && unscoped != null ) + @Override + public T get() + { + if ( value == null ) + { + synchronized ( this ) { - provided = unscoped.get(); - state.provided.put( key, provided ); + if ( value == null ) + { + value = provider.get(); + } } - - return provided; } - }; + return value; + } } @SuppressWarnings( { "unchecked" } ) diff --git a/maven-core/src/test/java/org/apache/maven/session/scope/internal/SessionScopeTest.java b/maven-core/src/test/java/org/apache/maven/session/scope/internal/SessionScopeTest.java new file mode 100644 index 000000000000..099e4dddb8f5 --- /dev/null +++ b/maven-core/src/test/java/org/apache/maven/session/scope/internal/SessionScopeTest.java @@ -0,0 +1,132 @@ +package org.apache.maven.session.scope.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 javax.inject.Provider; + +import com.google.inject.Key; +import com.google.inject.OutOfScopeException; +import org.apache.maven.model.locator.DefaultModelLocator; +import org.apache.maven.model.locator.ModelLocator; +import org.apache.maven.plugin.DefaultPluginRealmCache; +import org.apache.maven.plugin.PluginRealmCache; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; + +public class SessionScopeTest { + + @Test + public void testScope() throws Exception + { + SessionScope scope = new SessionScope(); + + try + { + scope.seed( ModelLocator.class, new DefaultModelLocator() ); + fail( "Expected a " + OutOfScopeException.class.getName() + " exception to be thrown" ); + } + catch ( OutOfScopeException e ) + { + // expected + } + + Provider pml = scope.scope( Key.get( ModelLocator.class), new DefaultModelLocatorProvider() ); + assertNotNull( pml ); + try + { + pml.get(); + fail( "Expected a " + OutOfScopeException.class.getName() + " exception to be thrown" ); + } + catch ( OutOfScopeException e ) + { + // expected + } + + Provider pmst = scope.scope( Key.get( PluginRealmCache.class ), new DefaultPluginRealmCacheProvider() ); + assertNotNull( pmst ); + + scope.enter(); + + final DefaultModelLocator dml1 = new DefaultModelLocator(); + scope.seed( ModelLocator.class, dml1 ); + + assertSame( dml1, pml.get() ); + + PluginRealmCache mst1 = pmst.get(); + assertSame( mst1, pmst.get() ); + Provider pmst1 = scope.scope( Key.get( PluginRealmCache.class ), new DefaultPluginRealmCacheProvider() ); + assertNotNull( pmst1 ); + assertSame( mst1, pmst1.get() ); + + scope.enter(); + + pmst1 = scope.scope( Key.get( PluginRealmCache.class ), new DefaultPluginRealmCacheProvider() ); + assertNotNull( pmst1 ); + assertNotSame( mst1, pmst1.get() ); + + scope.exit(); + + assertSame( mst1, pmst.get() ); + + scope.exit(); + + try + { + pmst.get(); + fail( "Expected a " + OutOfScopeException.class.getName() + " exception to be thrown" ); + } + catch ( OutOfScopeException e ) + { + // expected + } + try + { + scope.seed( ModelLocator.class, new DefaultModelLocator() ); + fail( "Expected a " + OutOfScopeException.class.getName() + " exception to be thrown" ); + } + catch ( OutOfScopeException e ) + { + // expected + } + } + + private static class DefaultPluginRealmCacheProvider implements com.google.inject.Provider + { + @Override + public PluginRealmCache get() + { + return new DefaultPluginRealmCache(); + } + } + + private static class DefaultModelLocatorProvider implements com.google.inject.Provider + { + @Override + public ModelLocator get() + { + return new DefaultModelLocator(); + } + } + +} From 84cbe1ab2e22a12c2c108d1a0e5233f875475fff Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Tue, 11 Jan 2022 15:23:52 +0100 Subject: [PATCH 19/37] [MNG-7362] DefaultArtifactResolver has spurious "Failure detected" INFO log --- .../apache/maven/artifact/resolver/DefaultArtifactResolver.java | 1 - 1 file changed, 1 deletion(-) diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java index 2d1d8d9492d4..1968c1db41ae 100644 --- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java +++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java @@ -511,7 +511,6 @@ public ArtifactResolutionResult resolve( ArtifactResolutionRequest request ) if ( result.hasMetadataResolutionExceptions() || result.hasVersionRangeViolations() || result.hasCircularDependencyExceptions() ) { - logger.info( "Failure detected." ); return result; } From 99de6b49ee066c102737e4cb99af4be3edb257df Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Sun, 9 Jan 2022 23:58:40 +0100 Subject: [PATCH 20/37] [MNG-7380] Don't log non-threadsafe warning if only building a single module This closes #655 --- .../apache/maven/lifecycle/internal/builder/BuilderCommon.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderCommon.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderCommon.java index f5c8e3ea4802..25ab6a46a6e2 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderCommon.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderCommon.java @@ -98,7 +98,7 @@ public MavenExecutionPlan resolveBuildPlan( MavenSession session, MavenProject p lifecycleDebugLogger.debugProjectPlan( project, executionPlan ); - if ( session.getRequest().getDegreeOfConcurrency() > 1 ) + if ( session.getRequest().getDegreeOfConcurrency() > 1 && session.getProjects().size() > 1 ) { final Set unsafePlugins = executionPlan.getNonThreadSafePlugins(); if ( !unsafePlugins.isEmpty() ) From 72c483b52702687f5a4160e1fd317b01c03988d3 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sat, 8 Jan 2022 21:32:28 +0100 Subject: [PATCH 21/37] [MNG-7384] Upgrade Maven JAR Plugin to 3.2.2 --- pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pom.xml b/pom.xml index 102419305b62..3583a87e197f 100644 --- a/pom.xml +++ b/pom.xml @@ -487,6 +487,12 @@ under the License. + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.2 + org.apache.maven.plugins maven-release-plugin From 67ff80544866aa9256624d34a6e4178c3b913996 Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Mon, 17 Jan 2022 22:07:09 +0100 Subject: [PATCH 22/37] [MNG-7381] Shorten parallel builder thread name to artifactId, conditionally with groupId This closes #663 --- .../multithreaded/MultiThreadedBuilder.java | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java index 2688a6b4357c..1be0e42ead6b 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java @@ -19,8 +19,10 @@ * under the License. */ +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; @@ -127,13 +129,17 @@ private void multiThreadedProjectTaskSegmentBuild( ConcurrencyDependencyGraph an ThreadOutputMuxer muxer ) { + // gather artifactIds which are not unique so that the respective thread names can be extended with the groupId + Set duplicateArtifactIds = gatherDuplicateArtifactIds( projectBuildList.keySet() ); + // schedule independent projects for ( MavenProject mavenProject : analyzer.getRootSchedulableBuilds() ) { ProjectSegment projectSegment = projectBuildList.get( mavenProject ); logger.debug( "Scheduling: " + projectSegment.getProject() ); Callable cb = - createBuildCallable( rootSession, projectSegment, reactorContext, taskSegment, muxer ); + createBuildCallable( rootSession, projectSegment, reactorContext, taskSegment, muxer, + duplicateArtifactIds ); service.submit( cb ); } @@ -158,7 +164,8 @@ private void multiThreadedProjectTaskSegmentBuild( ConcurrencyDependencyGraph an ProjectSegment scheduledDependent = projectBuildList.get( mavenProject ); logger.debug( "Scheduling: " + scheduledDependent ); Callable cb = - createBuildCallable( rootSession, scheduledDependent, reactorContext, taskSegment, muxer ); + createBuildCallable( rootSession, scheduledDependent, reactorContext, taskSegment, muxer, + duplicateArtifactIds ); service.submit( cb ); } } @@ -180,7 +187,9 @@ private void multiThreadedProjectTaskSegmentBuild( ConcurrencyDependencyGraph an private Callable createBuildCallable( final MavenSession rootSession, final ProjectSegment projectBuild, final ReactorContext reactorContext, - final TaskSegment taskSegment, final ThreadOutputMuxer muxer ) + final TaskSegment taskSegment, + final ThreadOutputMuxer muxer, + final Set duplicateArtifactIds ) { return new Callable() { @@ -188,13 +197,18 @@ public ProjectSegment call() { final Thread currentThread = Thread.currentThread(); final String originalThreadName = currentThread.getName(); - currentThread.setName( "mvn-builder-" + projectBuild.getProject().getId() ); + final MavenProject project = projectBuild.getProject(); + + final String threadNameSuffix = duplicateArtifactIds.contains( project.getArtifactId() ) + ? project.getGroupId() + ":" + project.getArtifactId() + : project.getArtifactId(); + currentThread.setName( "mvn-builder-" + threadNameSuffix ); try { // muxer.associateThreadWithProjectSegment( projectBuild ); lifecycleModuleBuilder.buildProject( projectBuild.getSession(), rootSession, reactorContext, - projectBuild.getProject(), taskSegment ); + project, taskSegment ); // muxer.setThisModuleComplete( projectBuild ); return projectBuild; @@ -206,4 +220,18 @@ public ProjectSegment call() } }; } + + private Set gatherDuplicateArtifactIds( Set projects ) + { + Set artifactIds = new HashSet<>( projects.size() ); + Set duplicateArtifactIds = new HashSet<>(); + for ( MavenProject project : projects ) + { + if ( !artifactIds.add( project.getArtifactId() ) ) + { + duplicateArtifactIds.add( project.getArtifactId() ); + } + } + return duplicateArtifactIds; + } } From 27755123e30d46a73ede29cef5b4c340fcdc3fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Boutemy?= Date: Sun, 9 Jan 2022 19:22:55 +0100 Subject: [PATCH 23/37] [MNG-7385] improve repository metadata documentation --- .../legacy/metadata/ArtifactMetadata.java | 9 +-- .../src/main/mdo/metadata.mdo | 69 ++++++++++--------- .../src/site/apt/index.apt | 32 ++++++--- 3 files changed, 64 insertions(+), 46 deletions(-) diff --git a/maven-artifact/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadata.java b/maven-artifact/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadata.java index 7abdfbbe8a07..c97b4e77aefb 100644 --- a/maven-artifact/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadata.java +++ b/maven-artifact/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadata.java @@ -24,10 +24,10 @@ /** * Contains metadata about an artifact, and methods to retrieve/store it from an artifact repository. - * - * @author Brett Porter * TODO merge with artifactmetadatasource * TODO retrieval exception not appropriate for store + * + * @author Brett Porter */ public interface ArtifactMetadata { @@ -62,18 +62,19 @@ public interface ArtifactMetadata /** * Merge a new metadata set into this piece of metadata. + * TODO this should only be needed on the repository metadata {@link org.apache.maven.artifact.metadata.ArtifactMetadata} * * @param metadata the new metadata - * TODO this should only be needed on the repository metadata */ void merge( ArtifactMetadata metadata ); /** * Store the metadata in the local repository. + * TODO this should only be needed on the repository metadata {@link org.apache.maven.artifact.metadata.ArtifactMetadata} * * @param localRepository the local repository * @param remoteRepository the remote repository it came from - * TODO this should only be needed on the repository metadata + * @throws RepositoryMetadataStoreException in case of issue */ void storeInLocalRepository( ArtifactRepository localRepository, ArtifactRepository remoteRepository ) diff --git a/maven-repository-metadata/src/main/mdo/metadata.mdo b/maven-repository-metadata/src/main/mdo/metadata.mdo index a6f5299fa6e1..ddaeb0a56c26 100644 --- a/maven-repository-metadata/src/main/mdo/metadata.mdo +++ b/maven-repository-metadata/src/main/mdo/metadata.mdo @@ -24,11 +24,9 @@ under the License. repository-metadata Metadata Per-directory repository metadata, for directories representing un-versioned artifact, snapshot artifact - or a group containing Maven plugins.

-

Notice that most metadata content has a meaning when the directory represents - an artifact (groupId, artifactId, versioning), but - plugins is used when the directory represents a group.

]]> +

Per-directory repository metadata repository-metadata.xml.

+

A directory may represent 3 types of content: "groupId", "groupId/artifactId" or "groupId/artifactId/version".

+

Most metadata content has a meaning when the directory represents a "groupId/artifactId" (groupId, artifactId, versioning)

]]> @@ -51,19 +49,13 @@ under the License. groupId 1.0.0+ String - The groupId that this directory represents, if any. + The groupId when this directory represents "groupId/artifactId" or "groupId/artifactId/version". artifactId 1.0.0+ String - The artifactId that this directory represents, if any. - - - version - 1.0.0+ - String - The version that this directory represents, if any. It is used for artifact snapshots only. + The artifactId when this directory represents "groupId/artifactId" or "groupId/artifactId/version". versioning @@ -71,12 +63,21 @@ under the License. Versioning - Versioning information for the artifact. + Versioning information when this directory represents "groupId/artifactId" or "groupId/artifactId/version". + + + version + 1.0.0+ + String + -SNAPSHOT) when this directory represents a "groupId/artifactId/version" for a SNAPSHOT.]]> plugins 1.0.0+ - The set of plugin mappings for the group represented by this directory + The set of plugins when this directory represents a "groupId" (deprecated) + + @Deprecated + Plugin * @@ -213,42 +214,42 @@ under the License. Versioning 1.0.0+ - Versioning information for an artifact (un-versioned or snapshot) + Versioning information for "groupId/artifactId" or "groupId/artifactId/version" SNAPSHOT latest 1.0.0+ String - What the latest version in the directory is, including snapshots + What the last version added to the directory is, including both releases and snapshots ("groupId/artifactId" directory only) release 1.0.0+ String - What the latest version in the directory is, of the releases only - - - snapshot - 1.0.0+ - - Snapshot - - The current snapshot data in use for this version (artifact snapshots only) + What the last version added to the directory is, for the releases only ("groupId/artifactId" directory only) versions 1.0.0+ - Versions available of the artifact (both releases and snapshots) + Versions available of the artifact (both releases and snapshots) ("groupId/artifactId" directory only) String * - + lastUpdated 1.0.0+ String - When the metadata was last updated + When the metadata was last updated (both "groupId/artifactId" and "groupId/artifactId/version" directories) + + + snapshot + 1.0.0+ + + Snapshot + + The current snapshot data in use for this version ("groupId/artifactId/version" only) snapshotVersions @@ -283,7 +284,7 @@ under the License. Snapshot 1.0.0+ - Snapshot data for the current artifact version + Snapshot data for the last artifact corresponding to the SNAPSHOT base version timestamp @@ -322,7 +323,7 @@ under the License. extension 1.1.0+ String - The file extension of thesub-artifact. + The file extension of the sub-artifact. version @@ -338,10 +339,14 @@ under the License. + Plugin 1.0.0+ - Mapping information for a single plugin within this group + Mapping information for a single plugin within this group (deprecated). + + @Deprecated + NOTE: plugin version is _NOT_ included here, since it is resolved using a separate algorithm in plugins' artifact. diff --git a/maven-repository-metadata/src/site/apt/index.apt b/maven-repository-metadata/src/site/apt/index.apt index ed2bff9680bd..1a484f9f5c5e 100644 --- a/maven-repository-metadata/src/site/apt/index.apt +++ b/maven-repository-metadata/src/site/apt/index.apt @@ -27,26 +27,38 @@ Maven Repository Metadata Model This is strictly the model for Maven Repository Metadata, so really just plain objects. - Maven Repository Metadata is available in directories representing: - - [[1]] an un-versioned artifact: it gives informations about available versions of the artifact, + The metadata file name is: - [[2]] a snapshot artifact: it gives precise information on the snapshot, + * <<>> in a remote repository, - [[3]] a group containing Maven plugins artifacts: it gives informations on plugins available in this group. + * <<.xml>>> in a local repository, for metadata from a repository with <<>> identifier. [] - The metadata file name is: + Depending on what the directory represents ("groupId", "groupId/artifactId" or "groupId/artifactId/version"), + the Maven Repository Metadata file contains 3 different sets of metadata: - * <<>> in a remote repository, + [[1]] in a "groupId" directory: a "groupId" directory may contain Maven plugins artifacts, which are described in metadata's <<>> element, - * <<.xml>>> in a local repository, for metadata from a repository with <<>> identifier. + [[2]] in a "groupId/artifactId" directory: metadata describes <<>>, <<>> and <<>> element that + gives data about available versions (<<>>, <<>>, <<>> list and <<>>), + + [[3]] in a "groupId/artifactId/version" snapshot artifact directory: metadata describes <<>>, <<>>, <<>> (base version, i.e. ending in <<<-SNAPSHOT>>>) and + <<>> element that gives data about snaphot (<<>>, <<>> and <<>> list). Notice that a + release artifact directory is not expected to provide metadata. [] The following are generated from this model: - * {{{./apidocs/index.html}Java sources}} with Reader and Writers for the Xpp3 XML parser, to read and write <<>> files + * {{{./apidocs/index.html}Java sources}} with Reader and Writers for the Xpp3 XML parser, to read and write <<>> files, - * A {{{./repository-metadata.html}Descriptor Reference}} + * a {{{./repository-metadata.html}Descriptor Reference}}. + + Notice: data about plugins in a directory representing a groupId is deprecated and will be removed in a future Maven version. +~~ logic behind this: +~~ 1. MNG-7266: maven-compat will be removed from future Maven version +~~ 2. this will remove the code that updates plugins data: see MNG-7375/MPLUGIN-384 https://maven.apache.org/ref/3.8.4/maven-compat/apidocs/org/apache/maven/artifact/repository/metadata/GroupRepositoryMetadata.html +~~ 3. this will lead to inconsistent data: removing it will be safer/more clear +~~ but this logic still remains to be confirmed by clear consensus of the whole team + \ No newline at end of file From 0cda42477253cab11e7e0f340009da5f417d0775 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 21 Jan 2022 16:53:03 +0100 Subject: [PATCH 24/37] [MNG-7386] Make sure the ModelMerger$MergingList can be serialized --- .../apache/maven/model/merge/ModelMerger.java | 9 +++- .../maven/model/merge/ModelMergerTest.java | 49 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 maven-model/src/test/java/org/apache/maven/model/merge/ModelMergerTest.java diff --git a/maven-model/src/main/java/org/apache/maven/model/merge/ModelMerger.java b/maven-model/src/main/java/org/apache/maven/model/merge/ModelMerger.java index dbd548b6c3c4..7b7ed4dd48f8 100644 --- a/maven-model/src/main/java/org/apache/maven/model/merge/ModelMerger.java +++ b/maven-model/src/main/java/org/apache/maven/model/merge/ModelMerger.java @@ -19,6 +19,7 @@ * under the License. */ +import java.io.ObjectStreamException; import java.util.AbstractList; import java.util.ArrayList; import java.util.Collection; @@ -2870,8 +2871,9 @@ private static List merge( List tgt, List src, KeyComputer compu * Merging list * @param */ - private static class MergingList extends AbstractList + private static class MergingList extends AbstractList implements java.io.Serializable { + private final KeyComputer keyComputer; private Map map; private List list; @@ -2882,6 +2884,11 @@ private static class MergingList extends AbstractList this.keyComputer = keyComputer; } + Object writeReplace() throws ObjectStreamException + { + return new ArrayList<>( this ); + } + @Override public Iterator iterator() { diff --git a/maven-model/src/test/java/org/apache/maven/model/merge/ModelMergerTest.java b/maven-model/src/test/java/org/apache/maven/model/merge/ModelMergerTest.java new file mode 100644 index 000000000000..c347cf63ce96 --- /dev/null +++ b/maven-model/src/test/java/org/apache/maven/model/merge/ModelMergerTest.java @@ -0,0 +1,49 @@ +package org.apache.maven.model.merge; + +/* + * 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.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; + +import org.apache.maven.model.License; +import org.apache.maven.model.Model; +import org.junit.Test; + +public class ModelMergerTest { + + @Test + public void testMergedModelSerialization() throws Exception { + Model target = new Model(); + Model source = new Model(); + target.setLicenses(new ArrayList()); + License lic1 = new License(); + License lic2 = new License(); + target.getLicenses().add(lic1); + source.setLicenses(new ArrayList()); + source.getLicenses().add(lic2); + + new ModelMerger().mergeModel(target, source, false, null); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(target); + } +} \ No newline at end of file From 83257bfde0dd5b4d391063412494957c1b7e15e8 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 24 Jan 2022 07:53:26 +0100 Subject: [PATCH 25/37] [MNG-7349] Limit relocation warning message to direct dependencies only --- .../DefaultPluginDependenciesResolver.java | 12 +++++++++++ .../DefaultProjectDependenciesResolver.java | 16 +++++++++++++++ .../DefaultArtifactDescriptorReader.java | 20 +++---------------- .../internal/RelocatedArtifact.java | 17 +++++++++++----- 4 files changed, 43 insertions(+), 22 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java index 8d16c6136671..c4bddc5f6aea 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java @@ -108,6 +108,18 @@ public Artifact resolve( Plugin plugin, List repositories, Rep pluginArtifact = result.getArtifact(); + if ( logger.isWarnEnabled() ) + { + if ( !result.getRelocations().isEmpty() ) + { + String message = pluginArtifact instanceof org.apache.maven.repository.internal.RelocatedArtifact + ? ( ( org.apache.maven.repository.internal.RelocatedArtifact ) pluginArtifact ).getMessage() + : null; + logger.warn( "The artifact " + result.getRelocations().get( 0 ) + " has been relocated to " + + pluginArtifact + ( message != null ? ": " + message : "" ) ); + } + } + String requiredMavenVersion = (String) result.getProperties().get( "prerequisites.maven" ); if ( requiredMavenVersion != null ) { 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 3644b67ef408..7ce49065d03d 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,6 +181,22 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request ) depRequest.setRoot( node ); + if ( logger.isWarnEnabled() ) + { + for ( DependencyNode child : node.getChildren() ) + { + if ( !child.getRelocations().isEmpty() ) + { + org.eclipse.aether.artifact.Artifact relocated = child.getDependency().getArtifact(); + String message = relocated instanceof org.apache.maven.repository.internal.RelocatedArtifact + ? ( ( org.apache.maven.repository.internal.RelocatedArtifact ) relocated ).getMessage() + : null; + logger.warn( "The artifact " + child.getRelocations().get( 0 ) + " has been relocated to " + + relocated + ( message != null ? ": " + message : "" ) ); + } + } + } + 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 888f4581b460..e78c77ff3224 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,8 +68,6 @@ 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 @@ -79,8 +77,6 @@ public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader, Service { - private static final Logger LOGGER = LoggerFactory.getLogger( DefaultArtifactDescriptorReader.class ); - private RemoteRepositoryManager remoteRepositoryManager; private VersionResolver versionResolver; @@ -320,20 +316,10 @@ private Model loadPom( RepositorySystemSession session, ArtifactDescriptorReques if ( relocation != null ) { result.addRelocation( a ); - Artifact relocatedArtifact = + a = new RelocatedArtifact( a, relocation.getGroupId(), relocation.getArtifactId(), - relocation.getVersion() ); - 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; + relocation.getVersion(), relocation.getMessage() ); + result.setArtifact( a ); } else { diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java index 4614ccfe5c5c..a0a21e9a6002 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java @@ -29,7 +29,7 @@ /** * @author Benjamin Bentmann */ -final class RelocatedArtifact +public final class RelocatedArtifact extends AbstractArtifact { @@ -41,13 +41,16 @@ final class RelocatedArtifact private final String version; - RelocatedArtifact( Artifact artifact, String groupId, String artifactId, String version ) + private final String message; + + RelocatedArtifact( Artifact artifact, String groupId, String artifactId, String version, String message ) { this.artifact = Objects.requireNonNull( artifact, "artifact cannot be null" ); // TODO Use StringUtils here this.groupId = ( groupId != null && groupId.length() > 0 ) ? groupId : null; this.artifactId = ( artifactId != null && artifactId.length() > 0 ) ? artifactId : null; this.version = ( version != null && version.length() > 0 ) ? version : null; + this.message = ( message != null && message.length() > 0 ) ? message : null; } public String getGroupId() @@ -95,7 +98,7 @@ public Artifact setVersion( String version ) { return this; } - return new RelocatedArtifact( artifact, groupId, artifactId, version ); + return new RelocatedArtifact( artifact, groupId, artifactId, version, message ); } @Override @@ -106,7 +109,7 @@ public Artifact setFile( File file ) { return this; } - return new RelocatedArtifact( artifact.setFile( file ), groupId, artifactId, version ); + return new RelocatedArtifact( artifact.setFile( file ), groupId, artifactId, version, message ); } @Override @@ -117,7 +120,7 @@ public Artifact setProperties( Map properties ) { return this; } - return new RelocatedArtifact( artifact.setProperties( properties ), groupId, artifactId, version ); + return new RelocatedArtifact( artifact.setProperties( properties ), groupId, artifactId, version, message ); } public String getClassifier() @@ -145,4 +148,8 @@ public Map getProperties() return artifact.getProperties(); } + public String getMessage() + { + return message; + } } From d79485ff23c9017d47424ff24da1d6dd3c414a60 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 1 Feb 2022 14:26:54 +0100 Subject: [PATCH 26/37] [MNG-6727] Using version range in parent and CI Friendly Version fails --- .../DefaultMavenProjectBuilderTest.java | 135 +++++++++++++++++- .../pom.xml | 12 ++ .../pom.xml | 4 +- .../pom.xml | 12 ++ .../pom.xml | 12 ++ .../pom.xml | 14 ++ .../child/pom.xml | 12 ++ .../pom.xml | 7 + .../child/pom.xml | 4 +- .../pom.xml | 7 + .../child/pom.xml | 14 ++ .../pom.xml | 0 .../model/building/DefaultModelBuilder.java | 20 ++- 13 files changed, 241 insertions(+), 12 deletions(-) create mode 100644 maven-core/src/test/resources/projects/parent-version-range-external-child-pom-parent-version-expression/pom.xml rename maven-core/src/test/resources/projects/{parent-version-range-external-child-version-expression => parent-version-range-external-child-pom-version-expression}/pom.xml (69%) create mode 100644 maven-core/src/test/resources/projects/parent-version-range-external-child-project-parent-version-expression/pom.xml create mode 100644 maven-core/src/test/resources/projects/parent-version-range-external-child-project-version-expression/pom.xml create mode 100644 maven-core/src/test/resources/projects/parent-version-range-external-child-revision-expression/pom.xml create mode 100644 maven-core/src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/child/pom.xml create mode 100644 maven-core/src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/pom.xml rename maven-core/src/test/resources/projects/{parent-version-range-local-child-version-expression => parent-version-range-local-child-project-version-expression}/child/pom.xml (70%) create mode 100644 maven-core/src/test/resources/projects/parent-version-range-local-child-project-version-expression/pom.xml create mode 100644 maven-core/src/test/resources/projects/parent-version-range-local-child-revision-expression/child/pom.xml rename maven-core/src/test/resources/projects/{parent-version-range-local-child-version-expression => parent-version-range-local-child-revision-expression}/pom.xml (100%) diff --git a/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java index 008c6d3bdc31..74a3a074e191 100644 --- a/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java @@ -298,11 +298,11 @@ public void testBuildParentVersionRangeLocallyWithoutChildVersion() throws Excep * * @throws Exception */ - public void testBuildParentVersionRangeLocallyWithChildVersionExpression() throws Exception + public void testBuildParentVersionRangeLocallyWithChildProjectVersionExpression() throws Exception { File f1 = getTestFile( - "src/test/resources/projects/parent-version-range-local-child-version-expression/child/pom.xml" ); + "src/test/resources/projects/parent-version-range-local-child-project-version-expression/child/pom.xml" ); try { @@ -315,7 +315,47 @@ public void testBuildParentVersionRangeLocallyWithChildVersionExpression() throw assertThat( e.getMessage(), containsString( "Version must be a constant" ) ); } } + + /** + * Tests whether local version range parent references are build correctly. + * + * @throws Exception + */ + public void testBuildParentVersionRangeLocallyWithChildProjectParentVersionExpression() throws Exception + { + File f1 = + getTestFile( + "src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/child/pom.xml" ); + try + { + getProject( f1 ); + fail( "Expected 'ProjectBuildingException' not thrown." ); + } + catch ( final ProjectBuildingException e ) + { + assertNotNull( e.getMessage() ); + assertThat( e.getMessage(), containsString( "Version must be a constant" ) ); + } + } + + /** + * Tests whether local version range parent references are build correctly. + * + * @throws Exception + */ + public void testBuildParentVersionRangeLocallyWithChildRevisionExpression() throws Exception + { + File f1 = + getTestFile( + "src/test/resources/projects/parent-version-range-local-child-revision-expression/child/pom.xml" ); + + MavenProject mp = this.getProjectFromRemoteRepository( f1 ); + + assertEquals("1.0-SNAPSHOT", mp.getVersion()); + + } + /** * Tests whether external version range parent references are build correctly. * @@ -363,11 +403,34 @@ public void testBuildParentVersionRangeExternallyWithoutChildVersion() throws Ex * * @throws Exception */ - public void testBuildParentVersionRangeExternallyWithChildVersionExpression() throws Exception + public void testBuildParentVersionRangeExternallyWithChildProjectVersionExpression() throws Exception { File f1 = getTestFile( - "src/test/resources/projects/parent-version-range-external-child-version-expression/pom.xml" ); + "src/test/resources/projects/parent-version-range-external-child-project-version-expression/pom.xml" ); + + try + { + this.getProjectFromRemoteRepository( f1 ); + fail( "Expected 'ProjectBuildingException' not thrown." ); + } + catch ( final ProjectBuildingException e ) + { + assertNotNull( e.getMessage() ); + assertThat( e.getMessage(), containsString( "Version must be a constant" ) ); + } + } + + /** + * Tests whether external version range parent references are build correctly. + * + * @throws Exception + */ + public void testBuildParentVersionRangeExternallyWithChildPomVersionExpression() throws Exception + { + File f1 = + getTestFile( + "src/test/resources/projects/parent-version-range-external-child-pom-version-expression/pom.xml" ); try { @@ -381,4 +444,68 @@ public void testBuildParentVersionRangeExternallyWithChildVersionExpression() th } } + /** + * Tests whether external version range parent references are build correctly. + * + * @throws Exception + */ + public void testBuildParentVersionRangeExternallyWithChildPomParentVersionExpression() throws Exception + { + File f1 = + getTestFile( + "src/test/resources/projects/parent-version-range-external-child-pom-parent-version-expression/pom.xml" ); + + try + { + this.getProjectFromRemoteRepository( f1 ); + fail( "Expected 'ProjectBuildingException' not thrown." ); + } + catch ( final ProjectBuildingException e ) + { + assertNotNull( e.getMessage() ); + assertThat( e.getMessage(), containsString( "Version must be a constant" ) ); + } + } + + /** + * Tests whether external version range parent references are build correctly. + * + * @throws Exception + */ + public void testBuildParentVersionRangeExternallyWithChildProjectParentVersionExpression() throws Exception + { + File f1 = + getTestFile( + "src/test/resources/projects/parent-version-range-external-child-project-parent-version-expression/pom.xml" ); + + try + { + this.getProjectFromRemoteRepository( f1 ); + fail( "Expected 'ProjectBuildingException' not thrown." ); + } + catch ( final ProjectBuildingException e ) + { + assertNotNull( e.getMessage() ); + assertThat( e.getMessage(), containsString( "Version must be a constant" ) ); + } + } + + /** + * Tests whether external version range parent references are build correctly. + * + * @throws Exception + */ + public void testBuildParentVersionRangeExternallyWithChildRevisionExpression() throws Exception + { + File f1 = + getTestFile( + "src/test/resources/projects/parent-version-range-external-child-revision-expression/pom.xml" ); + + + MavenProject mp = this.getProjectFromRemoteRepository( f1 ); + + assertEquals("1.0-SNAPSHOT", mp.getVersion()); + + + } } diff --git a/maven-core/src/test/resources/projects/parent-version-range-external-child-pom-parent-version-expression/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-external-child-pom-parent-version-expression/pom.xml new file mode 100644 index 000000000000..b37e54a9a987 --- /dev/null +++ b/maven-core/src/test/resources/projects/parent-version-range-external-child-pom-parent-version-expression/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + + org.apache + apache + [1,1] + + child + + ${pom.parent.version} + pom + diff --git a/maven-core/src/test/resources/projects/parent-version-range-external-child-version-expression/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-external-child-pom-version-expression/pom.xml similarity index 69% rename from maven-core/src/test/resources/projects/parent-version-range-external-child-version-expression/pom.xml rename to maven-core/src/test/resources/projects/parent-version-range-external-child-pom-version-expression/pom.xml index d07ad6eb565e..bd30a9af8e8d 100644 --- a/maven-core/src/test/resources/projects/parent-version-range-external-child-version-expression/pom.xml +++ b/maven-core/src/test/resources/projects/parent-version-range-external-child-pom-version-expression/pom.xml @@ -6,7 +6,7 @@ [1,1] child - - ${some.property} + + ${project.version} pom diff --git a/maven-core/src/test/resources/projects/parent-version-range-external-child-project-parent-version-expression/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-external-child-project-parent-version-expression/pom.xml new file mode 100644 index 000000000000..a8cf950fa2d9 --- /dev/null +++ b/maven-core/src/test/resources/projects/parent-version-range-external-child-project-parent-version-expression/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + + org.apache + apache + [1,1] + + child + + ${project.parent.version} + pom + diff --git a/maven-core/src/test/resources/projects/parent-version-range-external-child-project-version-expression/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-external-child-project-version-expression/pom.xml new file mode 100644 index 000000000000..bd30a9af8e8d --- /dev/null +++ b/maven-core/src/test/resources/projects/parent-version-range-external-child-project-version-expression/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + + org.apache + apache + [1,1] + + child + + ${project.version} + pom + diff --git a/maven-core/src/test/resources/projects/parent-version-range-external-child-revision-expression/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-external-child-revision-expression/pom.xml new file mode 100644 index 000000000000..aa724d854a05 --- /dev/null +++ b/maven-core/src/test/resources/projects/parent-version-range-external-child-revision-expression/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + + org.apache + apache + [1,1] + + child + ${revision} + pom + + 1.0-SNAPSHOT + + diff --git a/maven-core/src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/child/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/child/pom.xml new file mode 100644 index 000000000000..ac42c932b52d --- /dev/null +++ b/maven-core/src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/child/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + + parent-version-range-local + parent + [1,10] + + child + + ${project.parent.version} + pom + diff --git a/maven-core/src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/pom.xml new file mode 100644 index 000000000000..858cf1c3f014 --- /dev/null +++ b/maven-core/src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/pom.xml @@ -0,0 +1,7 @@ + + 4.0.0 + parent-version-range-local + parent + 1 + pom + diff --git a/maven-core/src/test/resources/projects/parent-version-range-local-child-version-expression/child/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-local-child-project-version-expression/child/pom.xml similarity index 70% rename from maven-core/src/test/resources/projects/parent-version-range-local-child-version-expression/child/pom.xml rename to maven-core/src/test/resources/projects/parent-version-range-local-child-project-version-expression/child/pom.xml index 066a11ecdb6c..1435070a8b96 100644 --- a/maven-core/src/test/resources/projects/parent-version-range-local-child-version-expression/child/pom.xml +++ b/maven-core/src/test/resources/projects/parent-version-range-local-child-project-version-expression/child/pom.xml @@ -6,7 +6,7 @@ [1,10] child - - ${some.property} + + ${project.version} pom diff --git a/maven-core/src/test/resources/projects/parent-version-range-local-child-project-version-expression/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-local-child-project-version-expression/pom.xml new file mode 100644 index 000000000000..858cf1c3f014 --- /dev/null +++ b/maven-core/src/test/resources/projects/parent-version-range-local-child-project-version-expression/pom.xml @@ -0,0 +1,7 @@ + + 4.0.0 + parent-version-range-local + parent + 1 + pom + diff --git a/maven-core/src/test/resources/projects/parent-version-range-local-child-revision-expression/child/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-local-child-revision-expression/child/pom.xml new file mode 100644 index 000000000000..b29b5d23bfc8 --- /dev/null +++ b/maven-core/src/test/resources/projects/parent-version-range-local-child-revision-expression/child/pom.xml @@ -0,0 +1,14 @@ + + 4.0.0 + + parent-version-range-local + parent + [1,10] + + child + ${revision} + pom + + 1.0-SNAPSHOT + + diff --git a/maven-core/src/test/resources/projects/parent-version-range-local-child-version-expression/pom.xml b/maven-core/src/test/resources/projects/parent-version-range-local-child-revision-expression/pom.xml similarity index 100% rename from maven-core/src/test/resources/projects/parent-version-range-local-child-version-expression/pom.xml rename to maven-core/src/test/resources/projects/parent-version-range-local-child-revision-expression/pom.xml 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 813b76297fe6..551f17a89858 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 @@ -1057,7 +1057,9 @@ private ModelData readParentLocally( Model childModel, ModelSource childSource, } // Validate versions aren't inherited when using parent ranges the same way as when read externally. - if ( childModel.getVersion() == null ) + String rawChildModelVersion = childModel.getVersion(); + + if ( rawChildModelVersion == null ) { // Message below is checked for in the MNG-2199 core IT. problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ) @@ -1066,7 +1068,7 @@ private ModelData readParentLocally( Model childModel, ModelSource childSource, } else { - if ( childModel.getVersion().contains( "${" ) ) + if ( rawChildVersionReferencesParent( rawChildModelVersion ) ) { // Message below is checked for in the MNG-2199 core IT. problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ) @@ -1099,6 +1101,14 @@ private ModelData readParentLocally( Model childModel, ModelSource childSource, return parentData; } + private boolean rawChildVersionReferencesParent( String rawChildModelVersion ) + { + return rawChildModelVersion.equals( "${pom.version}" ) + || rawChildModelVersion.equals( "${project.version}" ) + || rawChildModelVersion.equals( "${pom.parent.version}" ) + || rawChildModelVersion.equals( "${project.parent.version}" ); + } + private ModelSource getParentPomFile( Model childModel, ModelSource source ) { if ( !( source instanceof ModelSource2 ) ) @@ -1187,7 +1197,9 @@ public int getValidationLevel() if ( !parent.getVersion().equals( version ) ) { - if ( childModel.getVersion() == null ) + String rawChildModelVersion = childModel.getVersion(); + + if ( rawChildModelVersion == null ) { // Message below is checked for in the MNG-2199 core IT. problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ) @@ -1196,7 +1208,7 @@ public int getValidationLevel() } else { - if ( childModel.getVersion().contains( "${" ) ) + if ( rawChildVersionReferencesParent( rawChildModelVersion ) ) { // Message below is checked for in the MNG-2199 core IT. problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ) From 0a118d6e244e17cf27654ce6e17b1d3140c0967e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Boutemy?= Date: Sun, 6 Feb 2022 09:55:38 +0100 Subject: [PATCH 27/37] [MNG-7408] explain Maven 3 reporting plugin version selection --- maven-model/src/main/mdo/maven.mdo | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/maven-model/src/main/mdo/maven.mdo b/maven-model/src/main/mdo/maven.mdo index 61d9ceb6d5fe..5242d305353b 100644 --- a/maven-model/src/main/mdo/maven.mdo +++ b/maven-model/src/main/mdo/maven.mdo @@ -2835,7 +2835,12 @@ version 4.0.0+ - The version of the reporting plugin to be used. + + build/plugins then in build/pluginManagement. + ]]> + String From 6f141968464b4ad24e5d90f1389065141cda5e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Sat, 29 Jan 2022 18:09:47 +0100 Subject: [PATCH 28/37] [MNG-7400] Allow more WorkspaceReaders to participate This closes #668 --- .../java/org/apache/maven/DefaultMaven.java | 85 ++++++++++++------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java index 7f052c139d75..12b8f4ac7b4e 100644 --- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java +++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java @@ -232,26 +232,15 @@ private MavenExecutionResult doExecute( MavenExecutionRequest request, MavenSess return addExceptionToResult( result, e ); } - WorkspaceReader reactorWorkspace; try { - reactorWorkspace = container.lookup( WorkspaceReader.class, ReactorReader.HINT ); + setupWorkspaceReader( session, repoSession ); } catch ( ComponentLookupException e ) { return addExceptionToResult( result, e ); } - // - // Desired order of precedence for local artifact repositories - // - // Reactor - // Workspace - // User Local Repository - // - repoSession.setWorkspaceReader( ChainedWorkspaceReader.newInstance( reactorWorkspace, - repoSession.getWorkspaceReader() ) ); - repoSession.setReadOnly(); ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); @@ -326,6 +315,34 @@ private MavenExecutionResult doExecute( MavenExecutionRequest request, MavenSess return result; } + private void setupWorkspaceReader( MavenSession session, DefaultRepositorySystemSession repoSession ) + throws ComponentLookupException + { + // Desired order of precedence for workspace readers before querying the local artifact repositories + List workspaceReaders = new ArrayList(); + // 1) Reactor workspace reader + workspaceReaders.add( container.lookup( WorkspaceReader.class, ReactorReader.HINT ) ); + // 2) Repository system session-scoped workspace reader + WorkspaceReader repoWorkspaceReader = repoSession.getWorkspaceReader(); + if ( repoWorkspaceReader != null ) + { + workspaceReaders.add( repoWorkspaceReader ); + } + // 3) .. n) Project-scoped workspace readers + for ( WorkspaceReader workspaceReader : getProjectScopedExtensionComponents( session.getProjects(), + WorkspaceReader.class ) ) + { + if ( workspaceReaders.contains( workspaceReader ) ) + { + continue; + } + workspaceReaders.add( workspaceReader ); + } + WorkspaceReader[] readers = workspaceReaders.toArray( new WorkspaceReader[0] ); + repoSession.setWorkspaceReader( new ChainedWorkspaceReader( readers ) ); + + } + private void afterSessionEnd( Collection projects, MavenSession session ) throws MavenExecutionException { @@ -369,47 +386,57 @@ private Collection getLifecycleParticipants( { Collection lifecycleListeners = new LinkedHashSet<>(); - ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); try { - try - { - lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) ); - } - catch ( ComponentLookupException e ) - { - // this is just silly, lookupList should return an empty list! - logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() ); - } + lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) ); + } + catch ( ComponentLookupException e ) + { + // this is just silly, lookupList should return an empty list! + logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() ); + } + + lifecycleListeners.addAll( getProjectScopedExtensionComponents( projects, + AbstractMavenLifecycleParticipant.class ) ); - Collection scannedRealms = new HashSet<>(); + return lifecycleListeners; + } + protected Collection getProjectScopedExtensionComponents( Collection projects, Class role ) + { + + Collection foundComponents = new LinkedHashSet<>(); + Collection scannedRealms = new HashSet<>(); + + Thread currentThread = Thread.currentThread(); + ClassLoader originalContextClassLoader = currentThread.getContextClassLoader(); + try + { for ( MavenProject project : projects ) { ClassLoader projectRealm = project.getClassRealm(); if ( projectRealm != null && scannedRealms.add( projectRealm ) ) { - Thread.currentThread().setContextClassLoader( projectRealm ); + currentThread.setContextClassLoader( projectRealm ); try { - lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) ); + foundComponents.addAll( container.lookupList( role ) ); } catch ( ComponentLookupException e ) { // this is just silly, lookupList should return an empty list! - logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() ); + logger.warn( "Failed to lookup " + role + ": " + e.getMessage() ); } } } + return foundComponents; } finally { - Thread.currentThread().setContextClassLoader( originalClassLoader ); + currentThread.setContextClassLoader( originalContextClassLoader ); } - - return lifecycleListeners; } private MavenExecutionResult addExceptionToResult( MavenExecutionResult result, Throwable e ) From 2bb1228de60e805b2f864254a0b1efef7e2d7dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Wed, 2 Feb 2022 10:00:56 +0100 Subject: [PATCH 29/37] [MNG-7407] Introduce a ModelVersionProcessor component to make CI Friendly Versions pluggable This closes #674 --- .../building/DefaultModelBuilderFactory.java | 12 +++- .../AbstractStringBasedModelInterpolator.java | 32 +++------ .../DefaultModelVersionProcessor.java | 69 +++++++++++++++++++ .../interpolation/ModelVersionProcessor.java | 47 +++++++++++++ .../validation/DefaultModelValidator.java | 27 ++++---- .../StringSearchModelInterpolatorTest.java | 5 +- .../validation/DefaultModelValidatorTest.java | 3 +- 7 files changed, 154 insertions(+), 41 deletions(-) create mode 100644 maven-model-builder/src/main/java/org/apache/maven/model/interpolation/DefaultModelVersionProcessor.java create mode 100644 maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelVersionProcessor.java diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java index 730c5a29fee7..86c9e19a94c0 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java @@ -24,7 +24,9 @@ import org.apache.maven.model.composition.DependencyManagementImporter; import org.apache.maven.model.inheritance.DefaultInheritanceAssembler; import org.apache.maven.model.inheritance.InheritanceAssembler; +import org.apache.maven.model.interpolation.DefaultModelVersionProcessor; import org.apache.maven.model.interpolation.ModelInterpolator; +import org.apache.maven.model.interpolation.ModelVersionProcessor; import org.apache.maven.model.interpolation.StringVisitorModelInterpolator; import org.apache.maven.model.io.DefaultModelReader; import org.apache.maven.model.io.ModelReader; @@ -133,12 +135,18 @@ protected ModelInterpolator newModelInterpolator() { UrlNormalizer normalizer = newUrlNormalizer(); PathTranslator pathTranslator = newPathTranslator(); - return new StringVisitorModelInterpolator().setPathTranslator( pathTranslator ).setUrlNormalizer( normalizer ); + return new StringVisitorModelInterpolator().setPathTranslator( pathTranslator ).setUrlNormalizer( normalizer ) + .setVersionPropertiesProcessor( newModelVersionPropertiesProcessor() ); + } + + protected ModelVersionProcessor newModelVersionPropertiesProcessor() + { + return new DefaultModelVersionProcessor(); } protected ModelValidator newModelValidator() { - return new DefaultModelValidator(); + return new DefaultModelValidator( newModelVersionPropertiesProcessor() ); } protected ModelNormalizer newModelNormalizer() diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java index 388671d78de2..4e535cd6455e 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java @@ -52,12 +52,6 @@ public abstract class AbstractStringBasedModelInterpolator implements ModelInterpolator { - public static final String SHA1_PROPERTY = "sha1"; - - public static final String CHANGELIST_PROPERTY = "changelist"; - - public static final String REVISION_PROPERTY = "revision"; - private static final List PROJECT_PREFIXES = Arrays.asList( "pom.", "project." ); private static final Collection TRANSLATED_PATH_EXPRESSIONS; @@ -88,9 +82,8 @@ public abstract class AbstractStringBasedModelInterpolator @Inject private UrlNormalizer urlNormalizer; - public AbstractStringBasedModelInterpolator() - { - } + @Inject + private ModelVersionProcessor versionProcessor; public AbstractStringBasedModelInterpolator setPathTranslator( PathTranslator pathTranslator ) { @@ -104,6 +97,12 @@ public AbstractStringBasedModelInterpolator setUrlNormalizer( UrlNormalizer urlN return this; } + public AbstractStringBasedModelInterpolator setVersionPropertiesProcessor( ModelVersionProcessor processor ) + { + this.versionProcessor = processor; + return this; + } + protected List createValueSources( final Model model, final File projectDir, final ModelBuildingRequest config, final ModelProblemCollector problems ) @@ -162,19 +161,8 @@ public Object getValue( String expression ) valueSources.add( new MapBasedValueSource( config.getUserProperties() ) ); // Overwrite existing values in model properties. Otherwise it's not possible - // to define the version via command line: mvn -Drevision=6.5.7 ... - if ( config.getSystemProperties().containsKey( REVISION_PROPERTY ) ) - { - modelProperties.put( REVISION_PROPERTY, config.getSystemProperties().get( REVISION_PROPERTY ) ); - } - if ( config.getSystemProperties().containsKey( CHANGELIST_PROPERTY ) ) - { - modelProperties.put( CHANGELIST_PROPERTY, config.getSystemProperties().get( CHANGELIST_PROPERTY ) ); - } - if ( config.getSystemProperties().containsKey( SHA1_PROPERTY ) ) - { - modelProperties.put( SHA1_PROPERTY, config.getSystemProperties().get( SHA1_PROPERTY ) ); - } + // to define them via command line e.g.: mvn -Drevision=6.5.7 ... + versionProcessor.overwriteModelProperties( modelProperties, config ); valueSources.add( new MapBasedValueSource( modelProperties ) ); valueSources.add( new MapBasedValueSource( config.getSystemProperties() ) ); diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/DefaultModelVersionProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/DefaultModelVersionProcessor.java new file mode 100644 index 000000000000..27e3469a3b8a --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/DefaultModelVersionProcessor.java @@ -0,0 +1,69 @@ +package org.apache.maven.model.interpolation; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Properties; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.apache.maven.model.building.ModelBuildingRequest; + +/** + * Maven default implementation of the {@link ModelVersionProcessor} to support + * CI Friendly Versions + */ +@Named +@Singleton +public class DefaultModelVersionProcessor + implements ModelVersionProcessor +{ + + private static final String SHA1_PROPERTY = "sha1"; + + private static final String CHANGELIST_PROPERTY = "changelist"; + + private static final String REVISION_PROPERTY = "revision"; + + @Override + public boolean isValidProperty( String property ) + { + return REVISION_PROPERTY.equals( property ) || CHANGELIST_PROPERTY.equals( property ) + || SHA1_PROPERTY.equals( property ); + } + + @Override + public void overwriteModelProperties( Properties modelProperties, ModelBuildingRequest request ) + { + if ( request.getSystemProperties().containsKey( REVISION_PROPERTY ) ) + { + modelProperties.put( REVISION_PROPERTY, request.getSystemProperties().get( REVISION_PROPERTY ) ); + } + if ( request.getSystemProperties().containsKey( CHANGELIST_PROPERTY ) ) + { + modelProperties.put( CHANGELIST_PROPERTY, request.getSystemProperties().get( CHANGELIST_PROPERTY ) ); + } + if ( request.getSystemProperties().containsKey( SHA1_PROPERTY ) ) + { + modelProperties.put( SHA1_PROPERTY, request.getSystemProperties().get( SHA1_PROPERTY ) ); + } + + } +} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelVersionProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelVersionProcessor.java new file mode 100644 index 000000000000..35ce15ea0de6 --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelVersionProcessor.java @@ -0,0 +1,47 @@ +package org.apache.maven.model.interpolation; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Properties; + +import org.apache.maven.model.building.ModelBuildingRequest; + +/** + * Allows a fixed set of properties that are valid inside a version and that could be overwritten for example on the + * commandline + */ +public interface ModelVersionProcessor +{ + + /** + * @param property the property to check + * @return true if this is a valid property for this processor + */ + boolean isValidProperty( String property ); + + /** + * This method is responsible for examining the request and possibly overwrite of the valid properties in the model + * + * @param modelProperties + * @param request + */ + void overwriteModelProperties( Properties modelProperties, ModelBuildingRequest request ); + +} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java index ad7e3c7e5a9f..f77321c16654 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java @@ -44,7 +44,7 @@ import org.apache.maven.model.building.ModelProblem.Version; import org.apache.maven.model.building.ModelProblemCollector; import org.apache.maven.model.building.ModelProblemCollectorRequest; -import org.apache.maven.model.interpolation.AbstractStringBasedModelInterpolator; +import org.apache.maven.model.interpolation.ModelVersionProcessor; import org.codehaus.plexus.util.StringUtils; import java.io.File; @@ -58,6 +58,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; @@ -72,11 +73,6 @@ public class DefaultModelValidator private static final Pattern CI_FRIENDLY_EXPRESSION = Pattern.compile( "\\$\\{(.+?)\\}" ); - private static final List CI_FRIENDLY_POSSIBLE_PROPERTY_NAMES = - Arrays.asList( AbstractStringBasedModelInterpolator.REVISION_PROPERTY, - AbstractStringBasedModelInterpolator.CHANGELIST_PROPERTY, - AbstractStringBasedModelInterpolator.SHA1_PROPERTY ); - private static final String ILLEGAL_FS_CHARS = "\\/:\"<>|?*"; private static final String ILLEGAL_VERSION_CHARS = ILLEGAL_FS_CHARS; @@ -87,6 +83,14 @@ public class DefaultModelValidator private final Set validIds = new HashSet<>(); + private ModelVersionProcessor versionProcessor; + + @Inject + public DefaultModelValidator( ModelVersionProcessor versionProcessor ) + { + this.versionProcessor = versionProcessor; + } + @Override public void validateRawModel( Model m, ModelBuildingRequest request, ModelProblemCollector problems ) { @@ -930,21 +934,14 @@ private boolean validateVersionNoExpression( String fieldName, ModelProblemColle return true; } - // - // Acceptable versions for continuous delivery - // - // changelist - // revision - // sha1 - // Matcher m = CI_FRIENDLY_EXPRESSION.matcher( string.trim() ); while ( m.find() ) { - if ( !CI_FRIENDLY_POSSIBLE_PROPERTY_NAMES.contains( m.group( 1 ) ) ) + String property = m.group( 1 ); + if ( !versionProcessor.isValidProperty( property ) ) { addViolation( problems, severity, version, fieldName, null, "contains an expression but should be a constant.", tracker ); - return false; } } diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringSearchModelInterpolatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringSearchModelInterpolatorTest.java index df10511cee2b..c95e37271e29 100644 --- a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringSearchModelInterpolatorTest.java +++ b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringSearchModelInterpolatorTest.java @@ -54,7 +54,8 @@ protected void setUp() throws Exception { super.setUp(); - interpolator = new StringSearchModelInterpolator(); + interpolator = + new StringSearchModelInterpolator().setVersionPropertiesProcessor( new DefaultModelVersionProcessor() ); } @@ -580,6 +581,7 @@ public void testFinalFieldsExcludedFromInterpolation() SimpleProblemCollector problems = new SimpleProblemCollector(); StringSearchModelInterpolator interpolator = new StringSearchModelInterpolator(); + interpolator.setVersionPropertiesProcessor( new DefaultModelVersionProcessor() ); interpolator.interpolateObject( new ClassWithFinalField(), new Model(), null, request, problems ); assertProblemFree( problems ); @@ -605,6 +607,7 @@ public void testLocationTrackerShouldBeExcludedFromInterpolation() SimpleProblemCollector problems = new SimpleProblemCollector(); StringSearchModelInterpolator interpolator = new StringSearchModelInterpolator(); + interpolator.setVersionPropertiesProcessor( new DefaultModelVersionProcessor() ); interpolator.interpolateObject( model, model, null, request, problems ); assertProblemFree( problems ); diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java index 3e07c57754a8..c5f92c7a1424 100644 --- a/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java +++ b/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java @@ -26,6 +26,7 @@ import org.apache.maven.model.building.DefaultModelBuildingRequest; import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.SimpleProblemCollector; +import org.apache.maven.model.interpolation.DefaultModelVersionProcessor; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import junit.framework.TestCase; @@ -95,7 +96,7 @@ protected void setUp() { super.setUp(); - validator = new DefaultModelValidator(); + validator = new DefaultModelValidator(new DefaultModelVersionProcessor() ); } @Override From a5acd3ec6095ea2ff50191576c33685c1d038c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Mon, 24 Jan 2022 14:02:13 +0100 Subject: [PATCH 30/37] [MNG-7395] Support interpolation in extensions.xml This adds support for property interpolation in extensions.xml to allow advanced use cases where one wants to contribute certain things via the commandline. This closes #673 --- .../BootstrapCoreExtensionManager.java | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java index a47326977d0e..4f9faaea6b3e 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java @@ -40,6 +40,10 @@ import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.interpolation.InterpolationException; +import org.codehaus.plexus.interpolation.Interpolator; +import org.codehaus.plexus.interpolation.MapBasedValueSource; +import org.codehaus.plexus.interpolation.StringSearchInterpolator; import org.codehaus.plexus.logging.Logger; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; @@ -83,14 +87,16 @@ public List loadCoreExtensions( MavenExecutionRequest reques { RepositorySystemSession repoSession = repositorySystemSessionFactory.newRepositorySession( request ); List repositories = RepositoryUtils.toRepos( request.getPluginArtifactRepositories() ); + Interpolator interpolator = createInterpolator( request ); - return resolveCoreExtensions( repoSession, repositories, providedArtifacts, extensions ); + return resolveCoreExtensions( repoSession, repositories, providedArtifacts, extensions, interpolator ); } private List resolveCoreExtensions( RepositorySystemSession repoSession, List repositories, Set providedArtifacts, - List configuration ) + List configuration, + Interpolator interpolator ) throws Exception { List extensions = new ArrayList<>(); @@ -99,7 +105,8 @@ private List resolveCoreExtensions( RepositorySystemSession for ( CoreExtension extension : configuration ) { - List artifacts = resolveExtension( extension, repoSession, repositories, dependencyFilter ); + List artifacts = resolveExtension( extension, repoSession, repositories, + dependencyFilter, interpolator ); if ( !artifacts.isEmpty() ) { extensions.add( createExtension( extension, artifacts ) ); @@ -127,18 +134,20 @@ private CoreExtensionEntry createExtension( CoreExtension extension, List resolveExtension( CoreExtension extension, RepositorySystemSession repoSession, - List repositories, DependencyFilter dependencyFilter ) + List repositories, DependencyFilter dependencyFilter, + Interpolator interpolator ) throws ExtensionResolutionException { try { - // TODO: enhance the PluginDependenciesResolver to provide a - // TODO: resolveCoreExtension method which uses a CoreExtension - // TODO: object instead of a Plugin as this makes no sense + /* TODO: Enhance the PluginDependenciesResolver to provide a + * resolveCoreExtension method which uses a CoreExtension + * object instead of a Plugin as this makes no sense. + */ Plugin plugin = new Plugin(); - plugin.setGroupId( extension.getGroupId() ); - plugin.setArtifactId( extension.getArtifactId() ); - plugin.setVersion( extension.getVersion() ); + plugin.setGroupId( interpolator.interpolate( extension.getGroupId() ) ); + plugin.setArtifactId( interpolator.interpolate( extension.getArtifactId() ) ); + plugin.setVersion( interpolator.interpolate( extension.getVersion() ) ); DependencyNode root = pluginDependenciesResolver .resolveCoreExtension( plugin, dependencyFilter, repositories, repoSession ); @@ -152,6 +161,18 @@ private List resolveExtension( CoreExtension extension, RepositorySyst { throw new ExtensionResolutionException( extension, e.getCause() ); } + catch ( InterpolationException e ) + { + throw new ExtensionResolutionException( extension, e ); + } + } + + private static Interpolator createInterpolator( MavenExecutionRequest request ) + { + StringSearchInterpolator interpolator = new StringSearchInterpolator(); + interpolator.addValueSource( new MapBasedValueSource( request.getUserProperties() ) ); + interpolator.addValueSource( new MapBasedValueSource( request.getSystemProperties() ) ); + return interpolator; } } From 395411fe3184b9692ed16bafa578b40cc0051784 Mon Sep 17 00:00:00 2001 From: Sylwester Lachiewicz Date: Wed, 1 Jan 2020 16:01:14 +0100 Subject: [PATCH 31/37] [MNG-7417] Several classes do not set properties properly for building requests This closes #306 --- .../project/artifact/MavenMetadataSource.java | 1 + .../AbstractCoreMavenComponentTestCase.java | 3 ++- .../maven/project/PomConstructionTest.java | 22 +++++++++---------- .../DefaultArtifactDescriptorReader.java | 15 ++++--------- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java b/maven-core/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java index ac55fb93eb4d..7de55e972abf 100644 --- a/maven-core/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java +++ b/maven-core/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java @@ -587,6 +587,7 @@ private ProjectRelocation retrieveRelocatedProject( Artifact artifact, MetadataR configuration.setProcessPlugins( false ); configuration.setRepositoryMerging( ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT ); configuration.setSystemProperties( getSystemProperties() ); + configuration.setUserProperties( new Properties() ); configuration.setRepositorySession( legacySupport.getRepositorySession() ); project = getProjectBuilder().build( pomArtifact, configuration ).getProject(); diff --git a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java index 179b8f974180..2feeae1a1291 100644 --- a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java +++ b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java @@ -143,7 +143,8 @@ protected MavenSession createMavenSession( File pom, Properties executionPropert .setLocalRepository( request.getLocalRepository() ) .setRemoteRepositories( request.getRemoteRepositories() ) .setPluginArtifactRepositories( request.getPluginArtifactRepositories() ) - .setSystemProperties( executionProperties ); + .setSystemProperties( executionProperties ) + .setUserProperties( new Properties() ); List projects = new ArrayList<>(); diff --git a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java index e44e60f023b7..9e7eb4f09758 100644 --- a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java @@ -254,7 +254,7 @@ public void testValidationErrorUponNonUniqueDependencyManagementKeyInProfile() public void testDuplicateDependenciesCauseLastDeclarationToBePickedInLenientMode() throws Exception { - PomTestWrapper pom = buildPom( "unique-dependency-key/deps", true, null ); + PomTestWrapper pom = buildPom( "unique-dependency-key/deps", true, null, null ); assertEquals( 1, ( (List) pom.getValue( "dependencies" ) ).size() ); assertEquals( "0.2", pom.getValue( "dependencies[1]/version" ) ); } @@ -1437,7 +1437,7 @@ public void testJdkActivation() Properties props = new Properties(); props.put( "java.version", "1.5.0_15" ); - PomTestWrapper pom = buildPom( "jdk-activation", props ); + PomTestWrapper pom = buildPom( "jdk-activation", props, null ); assertEquals( 3, pom.getMavenProject().getActiveProfiles().size() ); assertEquals( "PASSED", pom.getValue( "properties/jdkProperty3" ) ); assertEquals( "PASSED", pom.getValue( "properties/jdkProperty2" ) ); @@ -1534,7 +1534,7 @@ public void testInterpolationWithSystemProperty() { Properties sysProps = new Properties(); sysProps.setProperty( "system.property", "PASSED" ); - PomTestWrapper pom = buildPom( "system-property-interpolation", sysProps ); + PomTestWrapper pom = buildPom( "system-property-interpolation", sysProps, null ); assertEquals( "PASSED", pom.getValue( "name" ) ); } @@ -1681,7 +1681,7 @@ public void testCliPropsDominateProjectPropsDuringInterpolation() { Properties props = new Properties(); props.setProperty( "testProperty", "PASSED" ); - PomTestWrapper pom = buildPom( "interpolation-cli-wins", props ); + PomTestWrapper pom = buildPom( "interpolation-cli-wins", null, props ); assertEquals( "PASSED", pom.getValue( "properties/interpolatedProperty" ) ); } @@ -1838,17 +1838,17 @@ private void assertPathWithNormalizedFileSeparators( Object value ) private PomTestWrapper buildPom( String pomPath, String... profileIds ) throws Exception { - return buildPom( pomPath, null, profileIds ); + return buildPom( pomPath, null, null, profileIds ); } - private PomTestWrapper buildPom( String pomPath, Properties executionProperties, String... profileIds ) + private PomTestWrapper buildPom( String pomPath, Properties systemProperties, Properties userProperties, String... profileIds ) throws Exception { - return buildPom( pomPath, false, executionProperties, profileIds ); + return buildPom( pomPath, false, systemProperties, userProperties, profileIds ); } - private PomTestWrapper buildPom( String pomPath, boolean lenientValidation, Properties executionProperties, - String... profileIds ) + private PomTestWrapper buildPom( String pomPath, boolean lenientValidation, Properties systemProperties, + Properties userProperties, String... profileIds ) throws Exception { File pomFile = new File( testDirectory, pomPath ); @@ -1864,8 +1864,8 @@ private PomTestWrapper buildPom( String pomPath, boolean lenientValidation, Prop localRepoUrl = "file://" + localRepoUrl; config.setLocalRepository( repositorySystem.createArtifactRepository( "local", localRepoUrl, new DefaultRepositoryLayout(), null, null ) ); config.setActiveProfileIds( Arrays.asList( profileIds ) ); - config.setSystemProperties( executionProperties ); - config.setUserProperties( executionProperties ); + config.setSystemProperties( systemProperties ); + config.setUserProperties( userProperties ); config.setValidationLevel( lenientValidation ? ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 : ModelBuildingRequest.VALIDATION_LEVEL_STRICT ); 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 e78c77ff3224..8d57b6086790 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 @@ -274,8 +274,8 @@ private Model loadPom( RepositorySystemSession session, ArtifactDescriptorReques modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL ); modelRequest.setProcessPlugins( false ); modelRequest.setTwoPhaseBuilding( false ); - modelRequest.setSystemProperties( toProperties( session.getUserProperties(), - session.getSystemProperties() ) ); + modelRequest.setSystemProperties( toProperties( session.getSystemProperties() ) ); + modelRequest.setUserProperties( toProperties( session.getUserProperties() ) ); modelRequest.setModelCache( DefaultModelCache.newInstance( session ) ); modelRequest.setModelResolver( new DefaultModelResolver( session, trace.newChild( modelRequest ), request.getRequestContext(), artifactResolver, @@ -328,17 +328,10 @@ private Model loadPom( RepositorySystemSession session, ArtifactDescriptorReques } } - private Properties toProperties( Map dominant, Map recessive ) + private Properties toProperties( Map map ) { Properties props = new Properties(); - if ( recessive != null ) - { - props.putAll( recessive ); - } - if ( dominant != null ) - { - props.putAll( dominant ); - } + props.putAll( map ); return props; } From d29af9018b5c80177102aaab96bd37ed5fedf26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Fri, 25 Feb 2022 11:46:07 +0100 Subject: [PATCH 32/37] [MNG-7402] BuildListCalculator never detaches the classloader This closes #683 --- .../lifecycle/internal/BuildListCalculator.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java index 76454f810d47..4fef69b4a9c7 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java @@ -57,10 +57,18 @@ public ProjectBuildList calculateProjectBuilds( MavenSession session, List Date: Fri, 28 Aug 2020 22:35:15 +0300 Subject: [PATCH 33/37] [MNG-5180] Versioning's snapshot version list is not included in metadata merge Co-authored-by: Konrad Windszus This closes #684 --- maven-repository-metadata/pom.xml | 5 + .../src/main/mdo/metadata.mdo | 50 ++- .../repository/metadata/MetadataTest.java | 290 ++++++++++++++++++ 3 files changed, 340 insertions(+), 5 deletions(-) create mode 100644 maven-repository-metadata/src/test/java/org/apache/maven/artifact/repository/metadata/MetadataTest.java diff --git a/maven-repository-metadata/pom.xml b/maven-repository-metadata/pom.xml index 31c0418b0c98..a9951098471e 100644 --- a/maven-repository-metadata/pom.xml +++ b/maven-repository-metadata/pom.xml @@ -38,6 +38,11 @@ under the License. org.codehaus.plexus plexus-utils + + org.apache.maven.resolver + maven-resolver-api + test + diff --git a/maven-repository-metadata/src/main/mdo/metadata.mdo b/maven-repository-metadata/src/main/mdo/metadata.mdo index ddaeb0a56c26..6ce381d4a830 100644 --- a/maven-repository-metadata/src/main/mdo/metadata.mdo +++ b/maven-repository-metadata/src/main/mdo/metadata.mdo @@ -88,6 +88,11 @@ under the License. 1.0.0+ versions = new java.util.LinkedHashMap<>(); + // never convert from legacy to new format if either source or target is legacy format + if ( !v.getSnapshotVersions().isEmpty() ) + { + for ( SnapshotVersion sv : versioning.getSnapshotVersions() ) + { + String key = getSnapshotVersionKey( sv ); + versions.put( key, sv ); + } + // never convert from legacy format + if ( !versions.isEmpty() ) + { + for ( SnapshotVersion sv : v.getSnapshotVersions() ) + { + String key = getSnapshotVersionKey( sv ); + if ( !versions.containsKey( key ) ) + { + versions.put( key, sv ); + } + } + } + v.setSnapshotVersions( new java.util.ArrayList( versions.values() ) ); + } + + changed = true; + } } } } @@ -241,7 +277,7 @@ under the License. lastUpdated 1.0.0+ String - When the metadata was last updated (both "groupId/artifactId" and "groupId/artifactId/version" directories) + When the metadata was last updated (both "groupId/artifactId" and "groupId/artifactId/version" directories). The timestamp is expressed using UTC in the format yyyyMMddHHmmss. snapshot @@ -254,7 +290,7 @@ under the License. snapshotVersions 1.1.0+ - Information for each sub-artifact available in this artifact snapshot. + Information for each sub-artifact available in this artifact snapshot. This is only the most recent SNAPSHOT for each unique extension/classifier combination. SnapshotVersion * @@ -289,7 +325,7 @@ under the License. timestamp 1.0.0+ - The time it was deployed + The timestamp when this version was deployed. The timestamp is expressed using UTC in the format yyyyMMdd.HHmmss. String @@ -316,26 +352,30 @@ under the License. classifier 1.1.0+ String - The classifier of the sub-artifact. + The classifier of the sub-artifact. Each classifier and extension pair may only appear once. + true extension 1.1.0+ String - The file extension of the sub-artifact. + The file extension of the sub-artifact. Each classifier and extension pair may only appear once. + true version 1.1.0+ String The resolved snapshot version of the sub-artifact. + true updated 1.1.0+ String The timestamp when this version information was last updated. The timestamp is expressed using UTC in the format yyyyMMddHHmmss. + true diff --git a/maven-repository-metadata/src/test/java/org/apache/maven/artifact/repository/metadata/MetadataTest.java b/maven-repository-metadata/src/test/java/org/apache/maven/artifact/repository/metadata/MetadataTest.java new file mode 100644 index 000000000000..1bf00b5ec1cf --- /dev/null +++ b/maven-repository-metadata/src/test/java/org/apache/maven/artifact/repository/metadata/MetadataTest.java @@ -0,0 +1,290 @@ +package org.apache.maven.artifact.repository.metadata; + +/* + * 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.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class MetadataTest +{ + + Artifact artifact; + + Metadata target; + + @Before + public void before() + { + artifact = new DefaultArtifact( "myGroup:myArtifact:1.0-SNAPSHOT" ); + target = createMetadataFromArtifact( artifact ); + } + + /*--- START test common metadata ---*/ + @Test + public void mergeEmptyMetadata() + throws Exception + { + Metadata metadata = new Metadata(); + assertFalse( metadata.merge( new Metadata() ) ); + } + + @Test + public void mergeDifferentGAV() + throws Exception + { + // merge implicitly assumes that merge is only called on the same GAV and does not perform any validation here! + Metadata source = new Metadata(); + source.setArtifactId( "source-artifact" ); + source.setGroupId( "source-group" ); + source.setVersion( "2.0" ); + assertFalse( target.merge( source ) ); + assertEquals( "myArtifact", target.getArtifactId() ); + assertEquals( "myGroup", target.getGroupId() ); + assertEquals( "1.0-SNAPSHOT", target.getVersion() ); + } + /*--- END test common metadata ---*/ + + /*--- START test "groupId/artifactId/version" metadata ---*/ + @Test + public void mergeSnapshotWithEmptyList() + throws Exception + { + Snapshot snapshot = new Snapshot(); + snapshot.setBuildNumber( 3 ); + snapshot.setTimestamp( "20200710.072412" ); + target.getVersioning().setSnapshot( snapshot ); + target.getVersioning().setLastUpdated( "20200921071745" ); + SnapshotVersion sv = new SnapshotVersion(); + sv.setClassifier( "sources" ); + sv.setExtension( "jar" ); + sv.setUpdated( "20200710072412" ); + target.getVersioning().addSnapshotVersion( sv ); + + Metadata source = createMetadataFromArtifact( artifact ); + // nothing should be actually changed, but still merge returns true + assertTrue( target.merge( source ) ); + + // NOTE! Merge updates last updated to source + assertEquals( "20200921071745", source.getVersioning().getLastUpdated() ); + + assertEquals( "myArtifact", target.getArtifactId() ); + assertEquals( "myGroup", target.getGroupId() ); + + assertEquals( 3, target.getVersioning().getSnapshot().getBuildNumber() ); + assertEquals( "20200710.072412", target.getVersioning().getSnapshot().getTimestamp() ); + + assertEquals( 1, target.getVersioning().getSnapshotVersions().size() ); + assertEquals( "sources", target.getVersioning().getSnapshotVersions().get( 0 ).getClassifier() ); + assertEquals( "jar", target.getVersioning().getSnapshotVersions().get( 0 ).getExtension() ); + assertEquals( "20200710072412", target.getVersioning().getSnapshotVersions().get( 0 ).getUpdated() ); + } + + @Test + public void mergeWithSameSnapshotWithDifferentVersionsAndNewerLastUpdated() + { + Metadata source = createMetadataFromArtifact( artifact ); + Date before = new Date( System.currentTimeMillis() - 5000 ); + Date after = new Date( System.currentTimeMillis() ); + addSnapshotVersion( target.getVersioning(), "jar", before, "1", 1 ); + SnapshotVersion sv2 = + addSnapshotVersion( source.getVersioning(), "jar", after, "1.0-" + formatDate( after, true ) + "-2", 2 ); + SnapshotVersion sv3 = + addSnapshotVersion( source.getVersioning(), "pom", after, "1.0-" + formatDate( after, true ) + "-2", 2 ); + assertTrue( target.merge( source ) ); + Versioning actualVersioning = target.getVersioning(); + assertEquals( 2, actualVersioning.getSnapshotVersions().size() ); + assertEquals( sv2, actualVersioning.getSnapshotVersions().get( 0 ) ); + assertEquals( sv3, actualVersioning.getSnapshotVersions().get( 1 ) ); + assertEquals( formatDate( after, false ), actualVersioning.getLastUpdated() ); + assertEquals( formatDate( after, true ), actualVersioning.getSnapshot().getTimestamp() ); + assertEquals( 2, actualVersioning.getSnapshot().getBuildNumber() ); + } + + @Test + public void mergeWithSameSnapshotWithDifferentVersionsAndOlderLastUpdated() + { + Metadata source = createMetadataFromArtifact( artifact ); + Date before = new Date( System.currentTimeMillis() - 5000 ); + Date after = new Date( System.currentTimeMillis() ); + SnapshotVersion sv1 = addSnapshotVersion( target.getVersioning(), after, artifact ); + addSnapshotVersion( source.getVersioning(), before, artifact ); + // nothing should be updated, as the target was already updated at a later date than source + assertFalse( target.merge( source ) ); + assertEquals( 1, target.getVersioning().getSnapshotVersions().size() ); + assertEquals( sv1, target.getVersioning().getSnapshotVersions().get( 0 ) ); + assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() ); + assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() ); + } + + @Test + public void mergeWithSameSnapshotWithSameVersionAndTimestamp() + { + Metadata source = createMetadataFromArtifact( artifact ); + Date date = new Date(); + addSnapshotVersion( target.getVersioning(), date, artifact ); + SnapshotVersion sv1 = addSnapshotVersion( source.getVersioning(), date, artifact ); + // although nothing has changed merge returns true, as the last modified date is equal + // TODO: improve merge here? + assertTrue( target.merge( source ) ); + assertEquals( 1, target.getVersioning().getSnapshotVersions().size() ); + assertEquals( sv1, target.getVersioning().getSnapshotVersions().get( 0 ) ); + assertEquals( formatDate( date, false ), target.getVersioning().getLastUpdated() ); + assertEquals( formatDate( date, true ), target.getVersioning().getSnapshot().getTimestamp() ); + } + + @Test + public void mergeLegacyWithSnapshotLegacy() + { + Metadata source = createMetadataFromArtifact( artifact ); + Date before = new Date( System.currentTimeMillis() - 5000 ); + Date after = new Date( System.currentTimeMillis() ); + // legacy metadata did not have "versioning.snapshotVersions" + addSnapshotVersionLegacy( target.getVersioning(), before, 1 ); + addSnapshotVersionLegacy( source.getVersioning(), after, 2 ); + // although nothing has changed merge returns true, as the last modified date is equal + // TODO: improve merge here? + assertTrue( target.merge( source ) ); + assertEquals( 0, target.getVersioning().getSnapshotVersions().size() ); + assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() ); + assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() ); + } + + @Test + public void mergeLegacyWithSnapshot() + { + Metadata source = createMetadataFromArtifact( artifact ); + Date before = new Date( System.currentTimeMillis() - 5000 ); + Date after = new Date( System.currentTimeMillis() ); + // legacy metadata did not have "versioning.snapshotVersions" + addSnapshotVersionLegacy( target.getVersioning(), before, 1 ); + addSnapshotVersion( source.getVersioning(), after, artifact ); + // although nothing has changed merge returns true, as the last modified date is equal + // TODO: improve merge here? + assertTrue( target.merge( source ) ); + // never convert from legacy format to v1.1 format + assertEquals( 0, target.getVersioning().getSnapshotVersions().size() ); + assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() ); + assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() ); + } + + @Test + public void mergeWithSnapshotLegacy() + { + Metadata source = createMetadataFromArtifact( artifact ); + Date before = new Date( System.currentTimeMillis() - 5000 ); + Date after = new Date( System.currentTimeMillis() ); + addSnapshotVersion( target.getVersioning(), before, artifact ); + // legacy metadata did not have "versioning.snapshotVersions" + addSnapshotVersionLegacy( source.getVersioning(), after, 2 ); + // although nothing has changed merge returns true, as the last modified date is equal + // TODO: improve merge here? + assertTrue( target.merge( source ) ); + // the result must be legacy format as well + assertEquals( 0, target.getVersioning().getSnapshotVersions().size() ); + assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() ); + assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() ); + assertEquals( 2, target.getVersioning().getSnapshot().getBuildNumber() ); + } + /*-- END test "groupId/artifactId/version" metadata ---*/ + + /*-- START helper methods to populate metadata objects ---*/ + private static final String SNAPSHOT = "SNAPSHOT"; + + private static final String DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT = "yyyyMMdd.HHmmss"; + + private static final String DEFAULT_DATE_FORMAT = "yyyyMMddHHmmss"; + + private static String formatDate( Date date, boolean forSnapshotTimestamp ) + { + // logic from metadata.mdo, class "Versioning" + TimeZone timezone = TimeZone.getTimeZone( "UTC" ); + DateFormat fmt = + new SimpleDateFormat( forSnapshotTimestamp ? DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT : DEFAULT_DATE_FORMAT ); + fmt.setCalendar( new GregorianCalendar() ); + fmt.setTimeZone( timezone ); + return fmt.format( date ); + } + + private static Metadata createMetadataFromArtifact( Artifact artifact ) + { + Metadata metadata = new Metadata(); + metadata.setArtifactId( artifact.getArtifactId() ); + metadata.setGroupId( artifact.getGroupId() ); + metadata.setVersion( artifact.getVersion() ); + metadata.setVersioning( new Versioning() ); + return metadata; + } + + private static SnapshotVersion addSnapshotVersion( Versioning versioning, Date timestamp, Artifact artifact ) + { + int buildNumber = 1; + // this generates timestamped versions like maven-resolver-provider: + // https://github.com/apache/maven/blob/03df5f7c639db744a3597c7175c92c8e2a27767b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java#L79 + String version = artifact.getVersion(); + String qualifier = formatDate( timestamp, true ) + '-' + buildNumber; + version = version.substring( 0, version.length() - SNAPSHOT.length() ) + qualifier; + return addSnapshotVersion( versioning, artifact.getExtension(), timestamp, version, buildNumber ); + } + + private static SnapshotVersion addSnapshotVersion( Versioning versioning, String extension, Date timestamp, + String version, int buildNumber ) + { + Snapshot snapshot = new Snapshot(); + snapshot.setBuildNumber( buildNumber ); + snapshot.setTimestamp( formatDate( timestamp, true ) ); + + SnapshotVersion sv = new SnapshotVersion(); + sv.setExtension( extension ); + sv.setVersion( version ); + sv.setUpdated( formatDate( timestamp, false ) ); + versioning.addSnapshotVersion( sv ); + + // make the new snapshot the current one + versioning.setSnapshot( snapshot ); + versioning.setLastUpdatedTimestamp( timestamp ); + return sv; + } + + // the format written by Maven 2 + // (https://maven.apache.org/ref/2.2.1/maven-repository-metadata/repository-metadata.html) + private static void addSnapshotVersionLegacy( Versioning versioning, Date timestamp, int buildNumber ) + { + Snapshot snapshot = new Snapshot(); + snapshot.setBuildNumber( buildNumber ); + snapshot.setTimestamp( formatDate( timestamp, true ) ); + + versioning.setSnapshot( snapshot ); + versioning.setLastUpdatedTimestamp( timestamp ); + } + /*-- END helper methods to populate metadata objects ---*/ +} \ No newline at end of file From f0caf9c9b31e31abb91ca986fe8168867cd0ded2 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sun, 27 Feb 2022 19:27:25 +0100 Subject: [PATCH 34/37] [MNG-6960] Use RuntimeInformation instead of reading properties --- ...DefaultRepositorySystemSessionFactory.java | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java b/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java index 9c4cede1c2c3..3bb622caa8b2 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java +++ b/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java @@ -25,6 +25,7 @@ import org.apache.maven.eventspy.internal.EventSpyDispatcher; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.repository.internal.MavenRepositorySystemUtils; +import org.apache.maven.rtinfo.RuntimeInformation; import org.apache.maven.settings.Mirror; import org.apache.maven.settings.Proxy; import org.apache.maven.settings.Server; @@ -93,6 +94,9 @@ public class DefaultRepositorySystemSessionFactory @Inject MavenRepositorySystem mavenRepositorySystem; + @Inject + private RuntimeInformation runtimeInformation; + public DefaultRepositorySystemSession newRepositorySession( MavenExecutionRequest request ) { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); @@ -244,28 +248,10 @@ else if ( request.isUpdateSnapshots() ) private String getUserAgent() { - return "Apache-Maven/" + getMavenVersion() + " (Java " + System.getProperty( "java.version" ) + "; " + String version = runtimeInformation.getMavenVersion(); + version = version.isEmpty() ? version : "/" + version; + return "Apache-Maven" + version + " (Java " + System.getProperty( "java.version" ) + "; " + System.getProperty( "os.name" ) + " " + System.getProperty( "os.version" ) + ")"; } - private String getMavenVersion() - { - Properties props = new Properties(); - - try ( InputStream is = getClass().getResourceAsStream( - "/META-INF/maven/org.apache.maven/maven-core/pom.properties" ) ) - { - if ( is != null ) - { - props.load( is ); - } - } - catch ( IOException e ) - { - logger.debug( "Failed to read Maven version", e ); - } - - return props.getProperty( "version", "unknown-version" ); - } - } From 572d5260b9040bd063b3dc84ce51684b8379df10 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Thu, 3 Mar 2022 12:45:18 +0100 Subject: [PATCH 35/37] [MNG-7428] Upgrade Maven Parent to 35 --- pom.xml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 3583a87e197f..d2ad92952dfb 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven-parent - 34 + 35 ../pom/maven/pom.xml @@ -487,12 +487,6 @@ under the License. - - - org.apache.maven.plugins - maven-jar-plugin - 3.2.2 - org.apache.maven.plugins maven-release-plugin @@ -632,6 +626,13 @@ under the License. org.apache.maven.plugins maven-enforcer-plugin + + + org.codehaus.mojo + extra-enforcer-rules + 1.4 + + From cfeea9dac4c5a14c846382aa7a47a7d4e5f110f5 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sat, 5 Mar 2022 12:39:24 +0100 Subject: [PATCH 36/37] Remove unused imports --- .../internal/aether/DefaultRepositorySystemSessionFactory.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java b/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java index 3bb622caa8b2..60c6cf17a050 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java +++ b/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java @@ -54,11 +54,8 @@ import javax.inject.Inject; import javax.inject.Named; -import java.io.IOException; -import java.io.InputStream; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Properties; /** * @since 3.3.0 From 3599d3414f046de2324203b78ddcf9b5e4388aa0 Mon Sep 17 00:00:00 2001 From: Michael Osipov Date: Sat, 5 Mar 2022 12:41:04 +0100 Subject: [PATCH 37/37] [maven-release-plugin] prepare release maven-3.8.5 --- 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 f8be416504c6..7ff4127676e2 100644 --- a/apache-maven/pom.xml +++ b/apache-maven/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 apache-maven diff --git a/maven-artifact/pom.xml b/maven-artifact/pom.xml index 0ced0ebe53f0..fe5ff2511103 100644 --- a/maven-artifact/pom.xml +++ b/maven-artifact/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-artifact diff --git a/maven-builder-support/pom.xml b/maven-builder-support/pom.xml index 9851384a8034..873a183d0dce 100644 --- a/maven-builder-support/pom.xml +++ b/maven-builder-support/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-builder-support diff --git a/maven-compat/pom.xml b/maven-compat/pom.xml index c3715e6298be..f37f57af85a6 100644 --- a/maven-compat/pom.xml +++ b/maven-compat/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-compat diff --git a/maven-core/pom.xml b/maven-core/pom.xml index ab8c71379277..8936d2f339c2 100644 --- a/maven-core/pom.xml +++ b/maven-core/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-core diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml index c180c865ea66..179473f0e548 100644 --- a/maven-embedder/pom.xml +++ b/maven-embedder/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-embedder diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml index bf0b0f9f256a..49f7fcaedd8f 100644 --- a/maven-model-builder/pom.xml +++ b/maven-model-builder/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-model-builder diff --git a/maven-model/pom.xml b/maven-model/pom.xml index db70815c092a..727a4ca8ad2b 100644 --- a/maven-model/pom.xml +++ b/maven-model/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-model diff --git a/maven-plugin-api/pom.xml b/maven-plugin-api/pom.xml index ab836127524a..c94e6e4c5f31 100644 --- a/maven-plugin-api/pom.xml +++ b/maven-plugin-api/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-plugin-api diff --git a/maven-repository-metadata/pom.xml b/maven-repository-metadata/pom.xml index a9951098471e..eae2debf3781 100644 --- a/maven-repository-metadata/pom.xml +++ b/maven-repository-metadata/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-repository-metadata diff --git a/maven-resolver-provider/pom.xml b/maven-resolver-provider/pom.xml index 62ff3f26c60c..a3d38be2c40d 100644 --- a/maven-resolver-provider/pom.xml +++ b/maven-resolver-provider/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-resolver-provider diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml index 6391cf223fd1..a8c1624a348e 100644 --- a/maven-settings-builder/pom.xml +++ b/maven-settings-builder/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-settings-builder diff --git a/maven-settings/pom.xml b/maven-settings/pom.xml index 36dd1923ab1f..e66f11f4915e 100644 --- a/maven-settings/pom.xml +++ b/maven-settings/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-settings diff --git a/maven-slf4j-provider/pom.xml b/maven-slf4j-provider/pom.xml index d12d0aedffba..33631c887de1 100644 --- a/maven-slf4j-provider/pom.xml +++ b/maven-slf4j-provider/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.8.5-SNAPSHOT + 3.8.5 maven-slf4j-provider diff --git a/pom.xml b/pom.xml index d2ad92952dfb..c319cae26c92 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ under the License. maven - 3.8.5-SNAPSHOT + 3.8.5 pom Apache Maven @@ -76,7 +76,7 @@ under the License. ref/3-LATEST None **/package-info.java - 2021-11-14T09:14:52Z + 2022-03-05T11:30:01Z @@ -100,7 +100,7 @@ under the License. scm:git:https://gitbox.apache.org/repos/asf/maven.git scm:git:https://gitbox.apache.org/repos/asf/maven.git https://github.com/apache/maven/tree/${project.scm.tag} - maven-3.8.3 + maven-3.8.5 jira