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. diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 000000000000..3b82ac148897 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,121 @@ +# 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/ + + 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: 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" -f maven-integration-testing/pom.xml diff --git a/.gitignore b/.gitignore index f79c9285cd4c..e7c899857962 100644 --- a/.gitignore +++ b/.gitignore @@ -3,13 +3,14 @@ target/ .classpath .settings/ .svn/ -bin/ # Intellij *.ipr *.iml .idea -out/ .DS_Store /bootstrap /dependencies.xml .java-version +.factorypath +.checkstyle +.vscode/ diff --git a/Jenkinsfile b/Jenkinsfile index 5d5d998c0398..cb80d71c57c0 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 = ['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 @@ -41,7 +41,7 @@ node(jenkinsEnv.nodeSelection(osNode)) { def MAVEN_GOAL='verify' stage('Configure deploy') { - if (env.BRANCH_NAME == 'master'){ + if (env.BRANCH_NAME in ['master', 'maven-3.8.x', 'maven-3.9.x']){ MAVEN_GOAL='deploy' } } diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml index 7d85e7525202..bf5f377a0971 100644 --- a/apache-maven/pom.xml +++ b/apache-maven/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.6.3 + 3.9.0-SNAPSHOT apache-maven @@ -63,29 +63,10 @@ under the License. org.apache.maven.wagon wagon-http - shaded - - - org.apache.httpcomponents - httpclient - - - org.apache.httpcomponents - httpcore - - - org.apache.maven.wagon - wagon-http-shared - - - - org.jsoup - jsoup - runtime + org.apache.maven.wagon + wagon-file org.slf4j @@ -94,12 +75,16 @@ under the License. runtime - org.apache.maven.wagon - wagon-file + org.apache.maven.resolver + maven-resolver-connector-basic org.apache.maven.resolver - maven-resolver-connector-basic + maven-resolver-transport-file + + + org.apache.maven.resolver + maven-resolver-transport-http org.apache.maven.resolver @@ -136,7 +121,7 @@ under the License. maven-dependency-plugin jansi - META-INF/native/** + org/fusesource/jansi/internal/native/Windows/** @@ -319,6 +304,12 @@ under the License. + + + versionlessMavenDist + + ${project.artifactId} + diff --git a/apache-maven/src/bin/mvn b/apache-maven/src/bin/mvn index a554c661762d..dfa384b8e141 100755 --- a/apache-maven/src/bin/mvn +++ b/apache-maven/src/bin/mvn @@ -29,6 +29,10 @@ if [ -z "$MAVEN_SKIP_RC" ] ; then + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + if [ -f /etc/mavenrc ] ; then . /etc/mavenrc fi @@ -90,15 +94,14 @@ if $mingw ; then fi if [ -z "$JAVA_HOME" ] ; then - JAVACMD=`which java` + JAVACMD="`\\unset -f command; \\command -v java`" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then - echo "The JAVA_HOME environment variable is not defined correctly" >&2 - echo "This environment variable is needed to run this program" >&2 - echo "NB: JAVA_HOME should point to a JDK not a JRE" >&2 + echo "The JAVA_HOME environment variable is not defined correctly," >&2 + echo "this environment variable is needed to run this program." >&2 exit 1 fi diff --git a/apache-maven/src/bin/mvn.cmd b/apache-maven/src/bin/mvn.cmd index fd1b21e3f9bb..9fb4a98c7e24 100644 --- a/apache-maven/src/bin/mvn.cmd +++ b/apache-maven/src/bin/mvn.cmd @@ -35,8 +35,8 @@ @REM Execute a user defined script before this one if not "%MAVEN_SKIP_RC%"=="" goto skipRcPre @REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* :skipRcPre @setlocal @@ -54,21 +54,16 @@ set "JAVACMD=%JAVA_HOME%\bin\java.exe" :checkJCmd if exist "%JAVACMD%" goto chkMHome -echo The JAVA_HOME environment variable is not defined correctly >&2 -echo This environment variable is needed to run this program >&2 -echo NB: JAVA_HOME should point to a JDK not a JRE >&2 +echo The JAVA_HOME environment variable is not defined correctly, >&2 +echo this environment variable is needed to run this program. >&2 goto error :chkMHome -set "MAVEN_HOME=%~dp0.." -if not "%MAVEN_HOME%"=="" goto stripMHome +set "MAVEN_HOME=%~dp0" +set "MAVEN_HOME=%MAVEN_HOME:~0,-5%" +if not "%MAVEN_HOME%"=="" goto checkMCmd goto error -:stripMHome -if not "_%MAVEN_HOME:~-1%"=="_\" goto checkMCmd -set "MAVEN_HOME=%MAVEN_HOME:~0,-1%" -goto stripMHome - :checkMCmd if exist "%MAVEN_HOME%\bin\mvn.cmd" goto init goto error @@ -78,7 +73,7 @@ goto error set MAVEN_CMD_LINE_ARGS=%* -@REM Find the project basedir, i.e., the directory that contains the folder ".mvn". +@REM Find the project basedir, i.e., the directory that contains the directory ".mvn". @REM Fallback to current working directory if not found. set "MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%" @@ -156,7 +151,7 @@ goto endDetectBaseDir :baseDirNotFound if "_%EXEC_DIR:~-1%"=="_\" set "EXEC_DIR=%EXEC_DIR:~0,-1%" set "MAVEN_PROJECTBASEDIR=%EXEC_DIR%" -cd "%EXEC_DIR%" +cd /d "%EXEC_DIR%" :endDetectBaseDir diff --git a/apache-maven/src/bin/mvnDebug b/apache-maven/src/bin/mvnDebug index be495ff15d38..5f6095a988e0 100755 --- a/apache-maven/src/bin/mvnDebug +++ b/apache-maven/src/bin/mvnDebug @@ -22,12 +22,13 @@ # # Environment Variable Prerequisites # -# JAVA_HOME Must point at your Java Development Kit installation. -# MAVEN_OPTS (Optional) Java runtime options used when Maven is executed. -# MAVEN_SKIP_RC (Optional) Flag to disable loading of mavenrc files. +# JAVA_HOME Must point at your Java Development Kit installation. +# MAVEN_OPTS (Optional) Java runtime options used when Maven is executed. +# MAVEN_SKIP_RC (Optional) Flag to disable loading of mavenrc files. +# MAVEN_DEBUG_ADDRESS (Optional) Set the debug address. Default value is 8000 # ----------------------------------------------------------------------------- -MAVEN_DEBUG_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000" +MAVEN_DEBUG_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${MAVEN_DEBUG_ADDRESS:-8000}" echo Preparing to execute Maven in debug mode diff --git a/apache-maven/src/bin/mvnDebug.cmd b/apache-maven/src/bin/mvnDebug.cmd index 5f9a20a0267a..6a327ff55be2 100644 --- a/apache-maven/src/bin/mvnDebug.cmd +++ b/apache-maven/src/bin/mvnDebug.cmd @@ -20,14 +20,25 @@ @REM @REM Environment Variable Prerequisites @REM -@REM JAVA_HOME Must point at your Java Development Kit installation. -@REM MAVEN_BATCH_ECHO (Optional) Set to 'on' to enable the echoing of the batch commands. -@REM MAVEN_BATCH_PAUSE (Optional) set to 'on' to wait for a key stroke before ending. -@REM MAVEN_OPTS (Optional) Java runtime options used when Maven is executed. -@REM MAVEN_SKIP_RC (Optional) Flag to disable loading of mavenrc files. +@REM JAVA_HOME Must point at your Java Development Kit installation. +@REM MAVEN_BATCH_ECHO (Optional) Set to 'on' to enable the echoing of the batch commands. +@REM MAVEN_BATCH_PAUSE (Optional) set to 'on' to wait for a key stroke before ending. +@REM MAVEN_OPTS (Optional) Java runtime options used when Maven is executed. +@REM MAVEN_SKIP_RC (Optional) Flag to disable loading of mavenrc files. +@REM MAVEN_DEBUG_ADDRESS (Optional) Set the debug address. Default value is 8000 @REM ----------------------------------------------------------------------------- +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%"=="on" echo %MAVEN_BATCH_ECHO% + @setlocal -@set MAVEN_DEBUG_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 + +IF "%MAVEN_DEBUG_ADDRESS%"=="" @set MAVEN_DEBUG_ADDRESS=8000 + +@set MAVEN_DEBUG_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=%MAVEN_DEBUG_ADDRESS% @call "%~dp0"mvn.cmd %* diff --git a/apache-maven/src/conf/logging/simplelogger.properties b/apache-maven/src/conf/logging/simplelogger.properties index 64b331b4592c..8c4a5d1e4b0d 100644 --- a/apache-maven/src/conf/logging/simplelogger.properties +++ b/apache-maven/src/conf/logging/simplelogger.properties @@ -26,7 +26,5 @@ org.slf4j.simpleLogger.log.Sisu=info org.slf4j.simpleLogger.warnLevelString=WARNING # MNG-6181: mvn -X also prints all debug logging from HttpClient -# Be aware that the shaded packages are used -# org.apache.http -> org.apache.maven.wagon.providers.http.httpclient -org.slf4j.simpleLogger.log.org.apache.maven.wagon.providers.http.httpclient=off -org.slf4j.simpleLogger.log.org.apache.maven.wagon.providers.http.httpclient.wire=off +org.slf4j.simpleLogger.log.org.apache.http=off +org.slf4j.simpleLogger.log.org.apache.http.wire=off diff --git a/apache-maven/src/conf/settings.xml b/apache-maven/src/conf/settings.xml index e27c579cf6db..9a80350ff042 100644 --- a/apache-maven/src/conf/settings.xml +++ b/apache-maven/src/conf/settings.xml @@ -43,9 +43,9 @@ under the License. | values (values used when the setting is not specified) are provided. | |--> - + xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd"> + + maven-default-http-blocker + external:http:* + Pseudo repository to mirror external repositories initially using HTTP. + http://0.0.0.0/ + true + - + bin zip diff --git a/apache-maven/src/main/assembly/component.xml b/apache-maven/src/main/assembly/component.xml index fab2c55c5d5c..3413c4f0405a 100644 --- a/apache-maven/src/main/assembly/component.xml +++ b/apache-maven/src/main/assembly/component.xml @@ -16,8 +16,8 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> - + false @@ -63,12 +63,11 @@ under the License. - target/dependency/META-INF/native + target/dependency/org/fusesource/jansi/internal/native lib/jansi-native ** - 0755 src/bin diff --git a/apache-maven/src/main/assembly/dir.xml b/apache-maven/src/main/assembly/dir.xml index 580b2098d632..86737b586b9f 100644 --- a/apache-maven/src/main/assembly/dir.xml +++ b/apache-maven/src/main/assembly/dir.xml @@ -17,8 +17,8 @@ specific language governing permissions and limitations under the License. --> - + dir dir diff --git a/apache-maven/src/main/assembly/src.xml b/apache-maven/src/main/assembly/src.xml index 9f43a0a7984e..940467421a87 100644 --- a/apache-maven/src/main/assembly/src.xml +++ b/apache-maven/src/main/assembly/src.xml @@ -17,8 +17,8 @@ specific language governing permissions and limitations under the License. --> - + src zip diff --git a/apache-maven/src/site/apt/index.apt.vm b/apache-maven/src/site/apt/index.apt.vm new file mode 100644 index 000000000000..1d802661d98f --- /dev/null +++ b/apache-maven/src/site/apt/index.apt.vm @@ -0,0 +1,40 @@ +~~ 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. + + ----- + ${project.name} + ----- + Hervรฉ Boutemy + ----- + 2021-07-11 + ----- + +${project.name} + + ${project.description} + +* References + + * <<>> invocation can be customised through: + + * <<>> (since 3.8.2), <<>> and <<<$HOME/.mavenrc>>> scripts on Unix, + + * <<<%USERPROFILE%\\mavenrc_pre.bat>>> and <<<%USERPROFILE%\\mavenrc_pre.cmd>>> scripts on Windows, + + [] + + and these scripts calls can be disabled by setting <<>> environment variable. diff --git a/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java b/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java index 0d0543e2899d..257350c90510 100644 --- a/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java +++ b/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java @@ -26,6 +26,7 @@ import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.charset.StandardCharsets; /** * Tests that the global settings.xml shipped with the distribution is in good state. @@ -44,7 +45,7 @@ public void testValidGlobalSettings() File globalSettingsFile = new File( basedir, "src/conf/settings.xml" ); assertTrue( globalSettingsFile.getAbsolutePath(), globalSettingsFile.isFile() ); - try ( Reader reader = new InputStreamReader( new FileInputStream( globalSettingsFile ), "UTF-8" ) ) + try ( Reader reader = new InputStreamReader( new FileInputStream( globalSettingsFile ), StandardCharsets.UTF_8) ) { new SettingsXpp3Reader().read( reader ); } diff --git a/doap_Maven.rdf b/doap_Maven.rdf index 45b4e4bef3e4..f157b2fdde22 100644 --- a/doap_Maven.rdf +++ b/doap_Maven.rdf @@ -33,6 +33,83 @@ under the License. Latest stable release + 2022-06-06 + 3.8.6 + http://archive.apache.org/dist/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.zip + http://archive.apache.org/dist/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz + http://archive.apache.org/dist/maven/maven-3/3.8.6/source/apache-maven-3.8.6-src.zip + http://archive.apache.org/dist/maven/maven-3/3.8.6/source/apache-maven-3.8.6-src.tar.gz + + + + + Apache Maven 3.8.5 + 2022-03-05 + 3.8.5 + http://archive.apache.org/dist/maven/maven-3/3.8.5/binaries/apache-maven-3.8.5-bin.zip + http://archive.apache.org/dist/maven/maven-3/3.8.5/binaries/apache-maven-3.8.5-bin.tar.gz + http://archive.apache.org/dist/maven/maven-3/3.8.5/source/apache-maven-3.8.5-src.zip + http://archive.apache.org/dist/maven/maven-3/3.8.5/source/apache-maven-3.8.5-src.tar.gz + + + + + Apache Maven 3.8.4 + 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 + 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 + http://archive.apache.org/dist/maven/maven-3/3.8.2/binaries/apache-maven-3.8.2-bin.tar.gz + http://archive.apache.org/dist/maven/maven-3/3.8.2/source/apache-maven-3.8.2-src.zip + http://archive.apache.org/dist/maven/maven-3/3.8.2/source/apache-maven-3.8.2-src.tar.gz + + + + + Apache Maven 3.8.1 + 2021-04-04 + 3.8.1 + http://archive.apache.org/dist/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.zip + http://archive.apache.org/dist/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.tar.gz + http://archive.apache.org/dist/maven/maven-3/3.8.1/source/apache-maven-3.8.1-src.zip + http://archive.apache.org/dist/maven/maven-3/3.8.1/source/apache-maven-3.8.1-src.tar.gz + + + + + Apache Maven 3.6.3 + 2019-11-19 + 3.6.3 + http://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.zip + http://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz + http://archive.apache.org/dist/maven/maven-3/3.6.3/source/apache-maven-3.6.3-src.zip + http://archive.apache.org/dist/maven/maven-3/3.6.3/source/apache-maven-3.6.3-src.tar.gz + + + + + Apache Maven 3.6.2 2019-08-27 3.6.2 http://archive.apache.org/dist/maven/maven-3/3.6.2/binaries/apache-maven-3.6.2-bin.zip @@ -40,6 +117,8 @@ under the License. http://archive.apache.org/dist/maven/maven-3/3.6.2/source/apache-maven-3.6.2-src.zip http://archive.apache.org/dist/maven/maven-3/3.6.2/source/apache-maven-3.6.2-src.tar.gz + + Apache Maven 3.6.1 2019-04-04 diff --git a/maven-artifact/pom.xml b/maven-artifact/pom.xml index ef112321174a..212e886ca1e8 100644 --- a/maven-artifact/pom.xml +++ b/maven-artifact/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.6.3 + 3.9.0-SNAPSHOT maven-artifact diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepository.java b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepository.java index 0b33345c73b0..47839eadc6a8 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepository.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepository.java @@ -73,6 +73,12 @@ public interface ArtifactRepository @Deprecated void setBlacklisted( boolean blackListed ); + /** @since 3.8.1 **/ + boolean isBlocked(); + + /** @since 3.8.1 **/ + void setBlocked( boolean blocked ); + // // New interface methods for the repository system. // diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryPolicy.java b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryPolicy.java index 5a795e9205f2..5ce317f20561 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryPolicy.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryPolicy.java @@ -138,7 +138,7 @@ else if ( UPDATE_POLICY_DAILY.equals( updatePolicy ) ) else if ( updatePolicy.startsWith( UPDATE_POLICY_INTERVAL ) ) { String s = updatePolicy.substring( UPDATE_POLICY_INTERVAL.length() + 1 ); - int minutes = Integer.valueOf( s ); + int minutes = Integer.parseInt( s ); Calendar cal = Calendar.getInstance(); cal.add( Calendar.MINUTE, -minutes ); if ( cal.getTime().after( lastModified ) ) @@ -212,7 +212,7 @@ else if ( ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS.equals( policy ) ) else if ( policy != null && policy.startsWith( ArtifactRepositoryPolicy.UPDATE_POLICY_INTERVAL ) ) { String s = policy.substring( UPDATE_POLICY_INTERVAL.length() + 1 ); - return Integer.valueOf( s ); + return Integer.parseInt( s ); } else { diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/AbstractArtifactResolutionException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/AbstractArtifactResolutionException.java index b63428e71397..a2917b5cd8f6 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/AbstractArtifactResolutionException.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/AbstractArtifactResolutionException.java @@ -52,7 +52,7 @@ public class AbstractArtifactResolutionException private final String path; - static final String LS = System.getProperty( "line.separator" ); + static final String LS = System.lineSeparator(); @SuppressWarnings( "checkstyle:parameternumber" ) protected AbstractArtifactResolutionException( String message, diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java index 811bab2f5eb9..41a9ad153707 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java @@ -530,8 +530,16 @@ public int compareTo( Item item ) { return 0; // 1-0 = 1- (normalize) = 1 } - Item first = get( 0 ); - return first.compareTo( null ); + // Compare the entire list of items with null - not just the first one, MNG-6964 + for ( Item i : this ) + { + int result = i.compareTo( null ); + if ( result != 0 ) + { + return result; + } + } + return 0; } switch ( item.getType() ) { @@ -582,6 +590,32 @@ public String toString() } return buffer.toString(); } + + /** + * Return the contents in the same format that is used when you call toString() on a List. + */ + private String toListString() + { + StringBuilder buffer = new StringBuilder(); + buffer.append( "[" ); + for ( Item item : this ) + { + if ( buffer.length() > 1 ) + { + buffer.append( ", " ); + } + if ( item instanceof ListItem ) + { + buffer.append( ( (ListItem ) item ).toListString() ); + } + else + { + buffer.append( item ); + } + } + buffer.append( "]" ); + return buffer.toString(); + } } public ComparableVersion( String version ) @@ -765,10 +799,10 @@ public int hashCode() * @param args the version strings to parse and compare. You can pass arbitrary number of version strings and always * two adjacent will be compared */ - // CHECKSTYLE_ON: LineLength public static void main( String... args ) { - System.out.println( "Display parameters as parsed by Maven (in canonical form) and comparison result:" ); + System.out.println( "Display parameters as parsed by Maven (in canonical form and as a list of tokens) and" + + " comparison result:" ); if ( args.length == 0 ) { return; @@ -787,9 +821,10 @@ public static void main( String... args ) + ( ( compare == 0 ) ? "==" : ( ( compare < 0 ) ? "<" : ">" ) ) + ' ' + version ); } - System.out.println( String.valueOf( i++ ) + ". " + version + " == " + c.getCanonical() ); + System.out.println( ( i++ ) + ". " + version + " -> " + c.getCanonical() + "; tokens: " + c.items.toListString() ); prev = c; } } + // CHECKSTYLE_ON: LineLength } diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java index bbc6523607b7..3689b2e7abcb 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java @@ -91,7 +91,8 @@ public VersionRange cloneOf() *

* Some spec examples are: *
    - *
  • 1.0 Version 1.0
  • + *
  • 1.0 Version 1.0 as a recommended version
  • + *
  • [1.0] Version 1.0 explicitly only
  • *
  • [1.0,2.0) Versions 1.0 (included) to 2.0 (not included)
  • *
  • [1.0,2.0] Versions 1.0 to 2.0 (both included)
  • *
  • [1.5,) Versions 1.5 and higher
  • 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-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java index 70fc1d8ecc17..97fb46d55f8b 100644 --- a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java +++ b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java @@ -295,6 +295,21 @@ public void testVersionZeroEqualWithLeadingZeroes() checkVersionsArrayEqual( arr ); } + /** + * Test MNG-6964 edge cases + * for qualifiers that start with "-0.", which was showing A == C and B == C but A < B. + */ + public void testMng6964() + { + String a = "1-0.alpha"; + String b = "1-0.beta"; + String c = "1"; + + checkVersionsOrder( a, c ); // Now a < c, but before MNG-6964 they were equal + checkVersionsOrder( b, c ); // Now b < c, but before MNG-6964 they were equal + checkVersionsOrder( a, b ); // Should still be true + } + public void testLocaleIndependent() { Locale orig = Locale.getDefault(); diff --git a/maven-builder-support/pom.xml b/maven-builder-support/pom.xml index ca20b8c5868d..c01cc7ca1fb0 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.6.3 + 3.9.0-SNAPSHOT maven-builder-support diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/StringSource.java b/maven-builder-support/src/main/java/org/apache/maven/building/StringSource.java index f9d87c0ba649..7705804aa4b2 100644 --- a/maven-builder-support/src/main/java/org/apache/maven/building/StringSource.java +++ b/maven-builder-support/src/main/java/org/apache/maven/building/StringSource.java @@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; /** * Wraps an ordinary {@link CharSequence} as a source. @@ -62,7 +63,7 @@ public StringSource( CharSequence content, String location ) public InputStream getInputStream() throws IOException { - return new ByteArrayInputStream( content.getBytes( "UTF-8" ) ); + return new ByteArrayInputStream( content.getBytes( StandardCharsets.UTF_8 ) ); } @Override diff --git a/maven-compat/pom.xml b/maven-compat/pom.xml index 0fb684acd172..ed7bce84d794 100644 --- a/maven-compat/pom.xml +++ b/maven-compat/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.6.3 + 3.9.0-SNAPSHOT maven-compat @@ -99,6 +99,11 @@ under the License. wagon-provider-api + + org.mockito + mockito-core + test + org.apache.maven.wagon wagon-file diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/installer/DefaultArtifactInstaller.java b/maven-compat/src/main/java/org/apache/maven/artifact/installer/DefaultArtifactInstaller.java index a2529757c1cc..5deee382f948 100644 --- a/maven-compat/src/main/java/org/apache/maven/artifact/installer/DefaultArtifactInstaller.java +++ b/maven-compat/src/main/java/org/apache/maven/artifact/installer/DefaultArtifactInstaller.java @@ -123,6 +123,7 @@ else if ( metadata instanceof SnapshotArtifactRepositoryMetadata } Versioning versioning = new Versioning(); + // TODO Should this be changed for MNG-6754 too? versioning.updateTimestamp(); versioning.addVersion( artifact.getBaseVersion() ); if ( artifact.isRelease() ) diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepository.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepository.java index 16b82c507005..ef487b8ad347 100644 --- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepository.java +++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepository.java @@ -54,6 +54,8 @@ public class DefaultArtifactRepository private List mirroredRepositories = Collections.emptyList(); + private boolean blocked; + /** * Create a local repository or a test repository. * @@ -264,4 +266,14 @@ public void setMirroredRepositories( List mirroredRepositori } } + public boolean isBlocked() + { + return blocked; + } + + public void setBlocked( boolean blocked ) + { + this.blocked = blocked; + } + } 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; } diff --git a/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java b/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java index 9bcc38423485..a428da03f9bc 100644 --- a/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java +++ b/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java @@ -76,7 +76,7 @@ public static void mergePluginLists( PluginContainer childContainer, PluginConta String inherited = plugin.getInherited(); - if ( ( inherited != null ) && !Boolean.valueOf( inherited ) ) + if ( ( inherited != null ) && !Boolean.parseBoolean( inherited ) ) { it.remove(); } @@ -97,7 +97,7 @@ public static void mergePluginLists( PluginContainer childContainer, PluginConta // 2. the parent's flag is not set // 3. the parent's flag is set to true if ( !handleAsInheritance || ( parentInherited == null ) - || Boolean.valueOf( parentInherited ) ) + || Boolean.parseBoolean( parentInherited ) ) { Plugin childPlugin = childPlugins.get( parentPlugin.getKey() ); @@ -217,7 +217,7 @@ public static void mergePluginDefinitions( Plugin child, Plugin parent, boolean // from here to the end of the method is dealing with merging of the section. String parentInherited = parent.getInherited(); - boolean parentIsInherited = ( parentInherited == null ) || Boolean.valueOf( parentInherited ); + boolean parentIsInherited = ( parentInherited == null ) || Boolean.parseBoolean( parentInherited ); List parentExecutions = parent.getExecutions(); @@ -234,7 +234,7 @@ public static void mergePluginDefinitions( Plugin child, Plugin parent, boolean String inherited = parentExecution.getInherited(); boolean parentExecInherited = - parentIsInherited && ( ( inherited == null ) || Boolean.valueOf( inherited ) ); + parentIsInherited && ( ( inherited == null ) || Boolean.parseBoolean( inherited ) ); if ( !handleAsInheritance || parentExecInherited ) { diff --git a/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java b/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java index 81ea92d99a89..2071cecc740e 100644 --- a/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java +++ b/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java @@ -55,7 +55,6 @@ public class DefaultModelInheritanceAssembler implements ModelInheritanceAssembler { // TODO Remove this! - @SuppressWarnings( "unchecked" ) public void assembleBuildInheritance( Build childBuild, Build parentBuild, boolean handleAsInheritance ) { // The build has been set but we want to step in here and fill in @@ -307,7 +306,6 @@ private void assembleModelInheritance( Model child, Model parent, String childPa } // TODO Remove this! - @SuppressWarnings( "unchecked" ) private void assembleDependencyManagementInheritance( Model child, Model parent ) { DependencyManagement parentDepMgmt = parent.getDependencyManagement(); @@ -386,7 +384,7 @@ private static void mergeReportPluginLists( Reporting child, Reporting parent, b { String parentInherited = parentPlugin.getInherited(); - if ( !handleAsInheritance || ( parentInherited == null ) || Boolean.valueOf( parentInherited ) ) + if ( !handleAsInheritance || ( parentInherited == null ) || Boolean.parseBoolean( parentInherited ) ) { ReportPlugin assembledPlugin = parentPlugin; @@ -474,7 +472,7 @@ public static void mergeReportPluginDefinitions( ReportPlugin child, ReportPlugi // from here to the end of the method is dealing with merging of the section. String parentInherited = parent.getInherited(); - boolean parentIsInherited = ( parentInherited == null ) || Boolean.valueOf( parentInherited ); + boolean parentIsInherited = ( parentInherited == null ) || Boolean.parseBoolean( parentInherited ); List parentReportSets = parent.getReportSets(); @@ -527,7 +525,6 @@ else if ( handleAsInheritance && ( parentInherited == null ) ) } // TODO Remove this! - @SuppressWarnings( "unchecked" ) private void assembleDependencyInheritance( Model child, Model parent ) { Map depsMap = new LinkedHashMap<>(); diff --git a/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidationResult.java b/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidationResult.java index 5033b990d8f4..9e2966e92d94 100644 --- a/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidationResult.java +++ b/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidationResult.java @@ -30,7 +30,7 @@ public class ModelValidationResult { /** */ - private static final String NEWLINE = System.getProperty( "line.separator" ); + private static final String LS = System.lineSeparator(); /** */ private List messages; @@ -80,13 +80,13 @@ public String render( String indentation ) // } // else // { -// message.append( "There was " + messages.size() + " validation errors: " + NEWLINE ); +// message.append( "There was " + messages.size() + " validation errors: " + LS ); // } // for ( int i = 0; i < messages.size(); i++ ) { message.append( indentation ).append( '[' ).append( i ).append( "] " ).append( messages.get( i ) ).append( - NEWLINE ); + LS ); } return message.toString(); diff --git a/maven-compat/src/main/java/org/apache/maven/repository/DefaultMirrorSelector.java b/maven-compat/src/main/java/org/apache/maven/repository/DefaultMirrorSelector.java index 6fa2c554a7a6..adb562a6d091 100644 --- a/maven-compat/src/main/java/org/apache/maven/repository/DefaultMirrorSelector.java +++ b/maven-compat/src/main/java/org/apache/maven/repository/DefaultMirrorSelector.java @@ -41,6 +41,8 @@ public class DefaultMirrorSelector private static final String EXTERNAL_WILDCARD = "external:*"; + private static final String EXTERNAL_HTTP_WILDCARD = "external:http:*"; + public Mirror getMirror( ArtifactRepository repository, List mirrors ) { String repoId = repository.getId(); @@ -68,9 +70,14 @@ public Mirror getMirror( ArtifactRepository repository, List mirrors ) } /** - * This method checks if the pattern matches the originalRepository. Valid patterns: * = - * everything external:* = everything not on the localhost and not file based. repo,repo1 = repo - * or repo1 *,!repo1 = everything except repo1 + * This method checks if the pattern matches the originalRepository. Valid patterns: + *
      + *
    • {@code *} = everything,
    • + *
    • {@code external:*} = everything not on the localhost and not file based,
    • + *
    • {@code external:http:*} = any repository not on the localhost using HTTP,
    • + *
    • {@code repo,repo1} = {@code repo} or {@code repo1},
    • + *
    • {@code *,!repo1} = everything except {@code repo1}.
    • + *
    * * @param originalRepository to compare for a match. * @param pattern used for match. Currently only '*' is supported. @@ -115,6 +122,12 @@ else if ( EXTERNAL_WILDCARD.equals( repo ) && isExternalRepo( originalRepository result = true; // don't stop processing in case a future segment explicitly excludes this repo } + // check for external:http:* + else if ( EXTERNAL_HTTP_WILDCARD.equals( repo ) && isExternalHttpRepo( originalRepository ) ) + { + result = true; + // don't stop processing in case a future segment explicitly excludes this repo + } else if ( WILDCARD.equals( repo ) ) { result = true; @@ -136,8 +149,34 @@ static boolean isExternalRepo( ArtifactRepository originalRepository ) try { URL url = new URL( originalRepository.getUrl() ); - return !( url.getHost().equals( "localhost" ) || url.getHost().equals( "127.0.0.1" ) - || url.getProtocol().equals( "file" ) ); + return !( isLocal( url.getHost() ) || url.getProtocol().equals( "file" ) ); + } + catch ( MalformedURLException e ) + { + // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it + return false; + } + } + + private static boolean isLocal( String host ) + { + return "localhost".equals( host ) || "127.0.0.1".equals( host ); + } + + /** + * Checks the URL to see if this repository refers to a non-localhost repository using HTTP. + * + * @param originalRepository + * @return true if external. + */ + static boolean isExternalHttpRepo( ArtifactRepository originalRepository ) + { + try + { + URL url = new URL( originalRepository.getUrl() ); + return ( "http".equalsIgnoreCase( url.getProtocol() ) || "dav".equalsIgnoreCase( url.getProtocol() ) + || "dav:http".equalsIgnoreCase( url.getProtocol() ) + || "dav+http".equalsIgnoreCase( url.getProtocol() ) ) && !isLocal( url.getHost() ); } catch ( MalformedURLException e ) { @@ -146,7 +185,7 @@ static boolean isExternalRepo( ArtifactRepository originalRepository ) } } - static boolean matchesLayout( ArtifactRepository repository, Mirror mirror ) + static boolean matchesLayout( ArtifactRepository repository, Mirror mirror ) { return matchesLayout( RepositoryUtils.getLayout( repository ), mirror.getMirrorOfLayouts() ); } diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/LegacyRepositorySystem.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/LegacyRepositorySystem.java index e3e778120803..fd62e6c71315 100644 --- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/LegacyRepositorySystem.java +++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/LegacyRepositorySystem.java @@ -446,6 +446,8 @@ public List getEffectiveRepositories( ListJason van Zyl */ @@ -34,12 +38,16 @@ public class ArtifactDeployerTest { private ArtifactDeployer artifactDeployer; + private SessionScope sessionScope; + protected void setUp() throws Exception { super.setUp(); artifactDeployer = (ArtifactDeployer) lookup( ArtifactDeployer.ROLE ); + + sessionScope = lookup( SessionScope.class ); } protected String component() @@ -50,18 +58,28 @@ protected String component() public void testArtifactInstallation() throws Exception { - String artifactBasedir = new File( getBasedir(), "src/test/resources/artifact-install" ).getAbsolutePath(); + sessionScope.enter(); + try + { + sessionScope.seed(MavenSession.class, mock(MavenSession.class)); + + String artifactBasedir = new File( getBasedir(), "src/test/resources/artifact-install" ).getAbsolutePath(); - Artifact artifact = createArtifact( "artifact", "1.0" ); + Artifact artifact = createArtifact( "artifact", "1.0" ); - File file = new File( artifactBasedir, "artifact-1.0.jar" ); - assertEquals( "dummy", FileUtils.fileRead( file, "UTF-8" ).trim() ); + File file = new File( artifactBasedir, "artifact-1.0.jar" ); + assertEquals( "dummy", FileUtils.fileRead( file, "UTF-8" ).trim() ); - artifactDeployer.deploy( file, artifact, remoteRepository(), localRepository() ); + artifactDeployer.deploy( file, artifact, remoteRepository(), localRepository() ); - ArtifactRepository remoteRepository = remoteRepository(); - File deployedFile = new File( remoteRepository.getBasedir(), remoteRepository.pathOf( artifact ) ); - assertTrue( deployedFile.exists() ); - assertEquals( "dummy", FileUtils.fileRead( deployedFile, "UTF-8" ).trim() ); + ArtifactRepository remoteRepository = remoteRepository(); + File deployedFile = new File( remoteRepository.getBasedir(), remoteRepository.pathOf( artifact ) ); + assertTrue( deployedFile.exists() ); + assertEquals( "dummy", FileUtils.fileRead( deployedFile, "UTF-8" ).trim() ); + } + finally + { + sessionScope.exit(); + } } } \ No newline at end of file diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/installer/ArtifactInstallerTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/installer/ArtifactInstallerTest.java index 21bfb2b70b81..66ba9e968f97 100644 --- a/maven-compat/src/test/java/org/apache/maven/artifact/installer/ArtifactInstallerTest.java +++ b/maven-compat/src/test/java/org/apache/maven/artifact/installer/ArtifactInstallerTest.java @@ -23,6 +23,10 @@ import org.apache.maven.artifact.AbstractArtifactComponentTestCase; import org.apache.maven.artifact.Artifact; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.session.scope.internal.SessionScope; + +import static org.mockito.Mockito.mock; /** * @author Jason van Zyl @@ -32,12 +36,16 @@ public class ArtifactInstallerTest { private ArtifactInstaller artifactInstaller; + private SessionScope sessionScope; + protected void setUp() throws Exception { super.setUp(); artifactInstaller = (ArtifactInstaller) lookup( ArtifactInstaller.ROLE ); + + sessionScope = lookup( SessionScope.class ); } protected String component() @@ -48,14 +56,24 @@ protected String component() public void testArtifactInstallation() throws Exception { - String artifactBasedir = new File( getBasedir(), "src/test/resources/artifact-install" ).getAbsolutePath(); + sessionScope.enter(); + try + { + sessionScope.seed(MavenSession.class, mock(MavenSession.class)); + + String artifactBasedir = new File( getBasedir(), "src/test/resources/artifact-install" ).getAbsolutePath(); - Artifact artifact = createArtifact( "artifact", "1.0" ); + Artifact artifact = createArtifact( "artifact", "1.0" ); - File source = new File( artifactBasedir, "artifact-1.0.jar" ); + File source = new File( artifactBasedir, "artifact-1.0.jar" ); - artifactInstaller.install( source, artifact, localRepository() ); + artifactInstaller.install( source, artifact, localRepository() ); - assertLocalArtifactPresent( artifact ); + assertLocalArtifactPresent( artifact ); + } + finally + { + sessionScope.exit(); + } } } \ No newline at end of file diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolutionExceptionTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolutionExceptionTest.java index 059aa2c3dc8b..8b75149c0ce3 100644 --- a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolutionExceptionTest.java +++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolutionExceptionTest.java @@ -32,7 +32,7 @@ public class ArtifactResolutionExceptionTest extends TestCase { - private static final String LS = System.getProperty( "line.separator" ); + private static final String LS = System.lineSeparator(); public void testMissingArtifactMessageFormat() { diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/testutils/TestFileManager.java b/maven-compat/src/test/java/org/apache/maven/artifact/testutils/TestFileManager.java index 3cadd29da48e..01a1f17454cb 100644 --- a/maven-compat/src/test/java/org/apache/maven/artifact/testutils/TestFileManager.java +++ b/maven-compat/src/test/java/org/apache/maven/artifact/testutils/TestFileManager.java @@ -44,9 +44,8 @@ import java.util.Iterator; import java.util.List; -import junit.framework.Assert; - import org.codehaus.plexus.util.FileUtils; +import org.junit.Assert; public class TestFileManager { diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/StringWagon.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/StringWagon.java index 944cce62d71f..3a72b98e9a0c 100644 --- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/StringWagon.java +++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/StringWagon.java @@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -72,14 +73,7 @@ public void fillInputData( InputData inputData ) resource.setContentLength( content.length() ); resource.setLastModified( System.currentTimeMillis() ); - try - { - inputData.setInputStream( new ByteArrayInputStream( content.getBytes( "UTF-8" ) ) ); - } - catch ( UnsupportedEncodingException e ) - { - throw new Error( "broken JVM", e ); - } + inputData.setInputStream( new ByteArrayInputStream( content.getBytes( StandardCharsets.UTF_8 ) ) ); } else { diff --git a/maven-core/pom.xml b/maven-core/pom.xml index 1f52e1b63bad..5d7c10a0d9ee 100644 --- a/maven-core/pom.xml +++ b/maven-core/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.6.3 + 3.9.0-SNAPSHOT maven-core @@ -105,6 +105,14 @@ under the License. guice no_aop
    + + com.google.guava + guava + + + com.google.guava + failureaccess + javax.inject javax.inject @@ -118,6 +126,10 @@ under the License. org.codehaus.plexus plexus-classworlds + + org.codehaus.plexus + plexus-interpolation + org.codehaus.plexus plexus-component-annotations @@ -126,6 +138,10 @@ under the License. org.apache.commons commons-lang3 + + org.slf4j + slf4j-api + commons-jxpath commons-jxpath @@ -164,31 +180,6 @@ under the License. - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.codehaus.mojo - buildnumber-maven-plugin - [1.2,) - - create-timestamp - - - - - - - - - - @@ -229,16 +220,6 @@ under the License. org.codehaus.mojo buildnumber-maven-plugin - - create-noncanonicalrev - - create-timestamp - - - 'NON-CANONICAL_'yyyy-MM-dd'T'HH:mm:ssXXX_'${user.name}' - nonCanonicalRevision - - create-buildnumber @@ -247,7 +228,7 @@ under the License. false false - ${nonCanonicalRevision} + NON_CANONICAL diff --git a/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java b/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java index a746846a8b2f..810baaef38f6 100644 --- a/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java +++ b/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java @@ -29,7 +29,7 @@ import org.apache.maven.artifact.resolver.filter.ArtifactFilter; import org.apache.maven.artifact.resolver.filter.ExclusionSetFilter; -import org.apache.maven.extension.internal.CoreExportsProvider; +import org.apache.maven.extension.internal.CoreExports; /** * @author Jason van Zyl @@ -50,10 +50,10 @@ public class DefaultArtifactFilterManager @Inject public DefaultArtifactFilterManager( List delegates, - CoreExportsProvider coreExports ) + CoreExports coreExports ) { this.delegates = delegates; - this.coreArtifacts = coreExports.get().getExportedArtifacts(); + this.coreArtifacts = coreExports.getExportedArtifacts(); } private synchronized Set getExcludedArtifacts() 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..0fc818e7489b 100644 --- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java +++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java @@ -40,6 +40,7 @@ import org.apache.maven.execution.ProjectDependencyGraph; import org.apache.maven.graph.GraphBuilder; import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory; +import org.apache.maven.internal.aether.MavenChainedWorkspaceReader; import org.apache.maven.lifecycle.internal.ExecutionEventCatapult; import org.apache.maven.lifecycle.internal.LifecycleStarter; import org.apache.maven.model.Prerequisites; @@ -58,7 +59,6 @@ import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.repository.WorkspaceReader; -import org.eclipse.aether.util.repository.ChainedWorkspaceReader; /** * @author Jason van Zyl @@ -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(); @@ -302,6 +291,8 @@ private MavenExecutionResult doExecute( MavenExecutionRequest request, MavenSess validatePrerequisitesForNonMavenPluginProjects( session.getProjects() ); + validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() ); + lifecycleStarter.execute( session ); validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() ); @@ -326,6 +317,32 @@ 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 ); + } + repoSession.setWorkspaceReader( MavenChainedWorkspaceReader.of( workspaceReaders ) ); + } + 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 ) ); + + return lifecycleListeners; + } - Collection scannedRealms = new HashSet<>(); + 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 ) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 84662ff87551..66f9f3a8d4a3 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -20,17 +20,17 @@ */ import java.io.File; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Named; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.execution.MavenSession; @@ -41,6 +41,13 @@ import org.eclipse.aether.repository.WorkspaceRepository; import org.eclipse.aether.util.artifact.ArtifactIdUtils; +import javax.inject.Inject; +import javax.inject.Named; + +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toMap; + /** * An implementation of a workspace reader that knows how to search the Maven reactor for artifacts, either as packaged * jar if it has been built, or only compile output directory if packaging hasn't happened yet. @@ -57,32 +64,27 @@ class ReactorReader private static final Collection COMPILE_PHASE_TYPES = Arrays.asList( "jar", "ejb-client", "war", "rar", "ejb3", "par", "sar", "wsr", "har", "app-client" ); - private Map projectsByGAV; + private final MavenSession session; + private final Map projectsByGAV; + private final Map> projectsByGA; + private final WorkspaceRepository repository; - private Map> projectsByGA; + private Function projectIntoKey = + s -> ArtifactUtils.key( s.getGroupId(), s.getArtifactId(), s.getVersion() ); - private WorkspaceRepository repository; + private Function projectIntoVersionlessKey = + s -> ArtifactUtils.versionlessKey( s.getGroupId(), s.getArtifactId() ); @Inject ReactorReader( MavenSession session ) { - projectsByGAV = session.getProjectMap(); - - projectsByGA = new HashMap<>( projectsByGAV.size() * 2 ); - for ( MavenProject project : projectsByGAV.values() ) - { - String key = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() ); - - List projects = projectsByGA.get( key ); + this.session = session; + this.projectsByGAV = + session.getProjects().stream() + .collect( toMap( projectIntoKey, identity() ) ); - if ( projects == null ) - { - projects = new ArrayList<>( 1 ); - projectsByGA.put( key, projects ); - } - - projects.add( project ); - } + this.projectsByGA = projectsByGAV.values().stream() + .collect( groupingBy( projectIntoVersionlessKey ) ); repository = new WorkspaceRepository( "reactor", new HashSet<>( projectsByGAV.keySet() ) ); } @@ -119,23 +121,11 @@ public List findVersions( Artifact artifact ) { String key = ArtifactUtils.versionlessKey( artifact.getGroupId(), artifact.getArtifactId() ); - List projects = projectsByGA.get( key ); - if ( projects == null || projects.isEmpty() ) - { - return Collections.emptyList(); - } - - List versions = new ArrayList<>(); - - for ( MavenProject project : projects ) - { - if ( find( project, artifact ) != null ) - { - versions.add( project.getVersion() ); - } - } - - return Collections.unmodifiableList( versions ); + return Optional.ofNullable( projectsByGA.get( key ) ) + .orElse( Collections.emptyList() ).stream() + .filter( s -> Objects.nonNull( find( s, artifact ) ) ) + .map( MavenProject::getVersion ) + .collect( Collectors.collectingAndThen( Collectors.toList(), Collections::unmodifiableList ) ); } @Override @@ -190,6 +180,17 @@ else if ( !hasBeenPackaged( project ) ) return null; } + private File determinePreviouslyPackagedArtifactFile( MavenProject project, Artifact artifact ) + { + if ( artifact == null ) + { + return null; + } + + String fileName = String.format( "%s.%s", project.getBuild().getFinalName(), artifact.getExtension() ); + return new File( project.getBuild().getDirectory(), fileName ); + } + private boolean hasArtifactFileFromPackagePhase( Artifact projectArtifact ) { return projectArtifact != null && projectArtifact.getFile() != null && projectArtifact.getFile().exists(); @@ -218,28 +219,27 @@ private Artifact findMatchingArtifact( MavenProject project, Artifact requestedA return mainArtifact; } - for ( Artifact attachedArtifact : RepositoryUtils.toArtifacts( project.getAttachedArtifacts() ) ) - { - if ( attachedArtifactComparison( requestedArtifact, attachedArtifact ) ) - { - return attachedArtifact; - } - } - - return null; + return RepositoryUtils.toArtifacts( project.getAttachedArtifacts() ).stream() + .filter( isRequestedArtifact( requestedArtifact ) ) + .findFirst() + .orElse( null ); } - private boolean attachedArtifactComparison( Artifact requested, Artifact attached ) + /** + * We are taking as much as we can from the DefaultArtifact.equals(). The requested artifact has no file, so we want + * to remove that from the comparison. + * + * @param requestArtifact checked against the given artifact. + * @return true if equals, false otherwise. + */ + private Predicate isRequestedArtifact( Artifact requestArtifact ) { - // - // We are taking as much as we can from the DefaultArtifact.equals(). The requested artifact has no file so - // we want to remove that from the comparison. - // - return requested.getArtifactId().equals( attached.getArtifactId() ) - && requested.getGroupId().equals( attached.getGroupId() ) - && requested.getVersion().equals( attached.getVersion() ) - && requested.getExtension().equals( attached.getExtension() ) - && requested.getClassifier().equals( attached.getClassifier() ); + return s -> s.getArtifactId().equals( requestArtifact.getArtifactId() ) + && s.getGroupId().equals( requestArtifact.getGroupId() ) + && s.getVersion().equals( requestArtifact.getVersion() ) + && s.getExtension().equals( requestArtifact.getExtension() ) + && s.getClassifier().equals( requestArtifact.getClassifier() ); + } /** diff --git a/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java b/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java index c1e21c44be1f..579315628a1b 100644 --- a/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java +++ b/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java @@ -26,6 +26,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; import org.apache.maven.artifact.handler.ArtifactHandler; import org.apache.maven.artifact.handler.DefaultArtifactHandler; @@ -170,32 +172,21 @@ public static Dependency toDependency( org.apache.maven.artifact.Artifact artifa Artifact result = toArtifact( artifact ); - List excl = null; - if ( exclusions != null ) - { - excl = new ArrayList<>( exclusions.size() ); - for ( org.apache.maven.model.Exclusion exclusion : exclusions ) - { - excl.add( toExclusion( exclusion ) ); - } - } - + List excl = Optional.ofNullable( exclusions ) + .orElse( Collections.emptyList() ) + .stream() + .map( RepositoryUtils::toExclusion ) + .collect( Collectors.toList() ); return new Dependency( result, artifact.getScope(), artifact.isOptional(), excl ); } public static List toRepos( List repos ) { - if ( repos == null ) - { - return null; - } - - List results = new ArrayList<>( repos.size() ); - for ( ArtifactRepository repo : repos ) - { - results.add( toRepo( repo ) ); - } - return results; + return Optional.ofNullable( repos ) + .orElse( Collections.emptyList() ) + .stream() + .map( RepositoryUtils::toRepo ) + .collect( Collectors.toList() ); } public static RemoteRepository toRepo( ArtifactRepository repo ) @@ -210,6 +201,7 @@ public static RemoteRepository toRepo( ArtifactRepository repo ) builder.setAuthentication( toAuthentication( repo.getAuthentication() ) ); builder.setProxy( toProxy( repo.getProxy() ) ); builder.setMirroredRepositories( toRepos( repo.getMirroredRepositories() ) ); + builder.setBlocked( repo.isBlocked() ); result = builder.build(); } return result; @@ -315,11 +307,8 @@ public static Dependency toDependency( org.apache.maven.model.Dependency depende new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(), dependency.getClassifier(), null, dependency.getVersion(), props, stereotype ); - List exclusions = new ArrayList<>( dependency.getExclusions().size() ); - for ( org.apache.maven.model.Exclusion exclusion : dependency.getExclusions() ) - { - exclusions.add( toExclusion( exclusion ) ); - } + List exclusions = + dependency.getExclusions().stream().map( RepositoryUtils::toExclusion ).collect( Collectors.toList() ); Dependency result = new Dependency( artifact, dependency.getScope(), @@ -362,12 +351,7 @@ public ArtifactType get( String stereotypeId ) public static Collection toArtifacts( Collection artifactsToConvert ) { - List artifacts = new ArrayList<>(); - for ( org.apache.maven.artifact.Artifact a : artifactsToConvert ) - { - artifacts.add( toArtifact( a ) ); - } - return artifacts; + return artifactsToConvert.stream().map( RepositoryUtils::toArtifact ).collect( Collectors.toList() ); } public static WorkspaceRepository getWorkspace( RepositorySystemSession session ) diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/LegacyLocalRepositoryManager.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/LegacyLocalRepositoryManager.java index 634b63cefb3e..acd7d5f2c428 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/repository/LegacyLocalRepositoryManager.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/LegacyLocalRepositoryManager.java @@ -427,6 +427,15 @@ public void setMirroredRepositories( List mirroredRepositori { } + public boolean isBlocked() + { + return false; + } + + public void setBlocked( boolean blocked ) + { + } + } } diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/MavenArtifactRepository.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/MavenArtifactRepository.java index c330fda42862..46197a4558e2 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/repository/MavenArtifactRepository.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/MavenArtifactRepository.java @@ -57,6 +57,8 @@ public class MavenArtifactRepository private List mirroredRepositories = Collections.emptyList(); + private boolean blocked; + public MavenArtifactRepository() { } @@ -160,6 +162,8 @@ public String toString() sb.append( ", update => " ).append( releases.getUpdatePolicy() ).append( "]\n" ); } + sb.append( " blocked: " ).append( isBlocked() ).append( '\n' ); + return sb.toString(); } @@ -414,4 +418,14 @@ public void setMirroredRepositories( List mirroredRepositori } } + public boolean isBlocked() + { + return blocked; + } + + public void setBlocked( boolean blocked ) + { + this.blocked = blocked; + } + } diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java index 46c41b94e75d..4ebe33f2c1f7 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java @@ -165,7 +165,6 @@ protected static Versioning createVersioning( Snapshot snapshot ) { Versioning versioning = new Versioning(); versioning.setSnapshot( snapshot ); - versioning.updateTimestamp(); return versioning; } diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java index dd50c317481f..18d4e833a0f8 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java @@ -19,11 +19,12 @@ * under the License. */ +import java.util.List; +import java.util.function.Predicate; + import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Exclusion; -import java.util.List; - /** * Filter to exclude from a list of artifact patterns. */ @@ -38,31 +39,33 @@ public ExclusionArtifactFilter( List exclusions ) this.exclusions = exclusions; } + private Predicate sameArtifactId( Artifact artifact ) + { + return exclusion -> exclusion.getArtifactId().equals( artifact.getArtifactId() ); + } + + private Predicate sameGroupId( Artifact artifact ) + { + return exclusion -> exclusion.getGroupId().equals( artifact.getGroupId() ); + } + + private Predicate groupIdIsWildcard = exclusion -> WILDCARD.equals( exclusion.getGroupId() ); + + private Predicate artifactIdIsWildcard = exclusion -> WILDCARD.equals( exclusion.getArtifactId() ); + + private Predicate groupIdAndArtifactIdIsWildcard = groupIdIsWildcard.and( artifactIdIsWildcard ); + + private Predicate exclude( Artifact artifact ) + { + return groupIdAndArtifactIdIsWildcard + .or( groupIdIsWildcard.and( sameArtifactId( artifact ) ) ) + .or( artifactIdIsWildcard.and( sameGroupId( artifact ) ) ) + .or( sameGroupId( artifact ).and( sameArtifactId( artifact ) ) ); + } + @Override public boolean include( Artifact artifact ) { - for ( Exclusion exclusion : exclusions ) - { - if ( WILDCARD.equals( exclusion.getGroupId() ) && WILDCARD.equals( exclusion.getArtifactId() ) ) - { - return false; - } - if ( WILDCARD.equals( exclusion.getGroupId() ) - && exclusion.getArtifactId().equals( artifact.getArtifactId() ) ) - { - return false; - } - if ( WILDCARD.equals( exclusion.getArtifactId() ) - && exclusion.getGroupId().equals( artifact.getGroupId() ) ) - { - return false; - } - if ( exclusion.getGroupId().equals( artifact.getGroupId() ) - && exclusion.getArtifactId().equals( artifact.getArtifactId() ) ) - { - return false; - } - } - return true; + return !exclusions.stream().anyMatch( exclude( artifact ) ); } } diff --git a/maven-core/src/main/java/org/apache/maven/bridge/MavenRepositorySystem.java b/maven-core/src/main/java/org/apache/maven/bridge/MavenRepositorySystem.java index 730b428221d0..72e8b4fbca98 100644 --- a/maven-core/src/main/java/org/apache/maven/bridge/MavenRepositorySystem.java +++ b/maven-core/src/main/java/org/apache/maven/bridge/MavenRepositorySystem.java @@ -190,6 +190,7 @@ private Mirror getMirror( RepositorySystemSession session, ArtifactRepository re mirror.setId( repo.getId() ); mirror.setUrl( repo.getUrl() ); mirror.setLayout( repo.getContentType() ); + mirror.setBlocked( repo.isBlocked() ); return mirror; } } @@ -226,6 +227,8 @@ private void injectMirror( ArtifactRepository repository, Mirror mirror ) { repository.setLayout( getLayout( mirror.getLayout() ) ); } + + repository.setBlocked( mirror.isBlocked() ); } } @@ -671,6 +674,8 @@ public List getEffectiveRepositories( List mirrors ) { String repoId = repository.getId(); @@ -737,8 +744,14 @@ public static Mirror getMirror( ArtifactRepository repository, List mirr } /** - * This method checks if the pattern matches the originalRepository. Valid patterns: * = everything external:* = - * everything not on the localhost and not file based. repo,repo1 = repo or repo1 *,!repo1 = everything except repo1 + * This method checks if the pattern matches the originalRepository. Valid patterns: + *
      + *
    • {@code *} = everything,
    • + *
    • {@code external:*} = everything not on the localhost and not file based,
    • + *
    • {@code external:http:*} = any repository not on the localhost using HTTP,
    • + *
    • {@code repo,repo1} = {@code repo} or {@code repo1},
    • + *
    • {@code *,!repo1} = everything except {@code repo1}.
    • + *
    * * @param originalRepository to compare for a match. * @param pattern used for match. Currently only '*' is supported. @@ -782,6 +795,12 @@ else if ( EXTERNAL_WILDCARD.equals( repo ) && isExternalRepo( originalRepository result = true; // don't stop processing in case a future segment explicitly excludes this repo } + // check for external:http:* + else if ( EXTERNAL_HTTP_WILDCARD.equals( repo ) && isExternalHttpRepo( originalRepository ) ) + { + result = true; + // don't stop processing in case a future segment explicitly excludes this repo + } else if ( WILDCARD.equals( repo ) ) { result = true; @@ -803,8 +822,34 @@ static boolean isExternalRepo( ArtifactRepository originalRepository ) try { URL url = new URL( originalRepository.getUrl() ); - return !( url.getHost().equals( "localhost" ) || url.getHost().equals( "127.0.0.1" ) - || url.getProtocol().equals( "file" ) ); + return !( isLocal( url.getHost() ) || url.getProtocol().equals( "file" ) ); + } + catch ( MalformedURLException e ) + { + // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it + return false; + } + } + + private static boolean isLocal( String host ) + { + return "localhost".equals( host ) || "127.0.0.1".equals( host ); + } + + /** + * Checks the URL to see if this repository refers to a non-localhost repository using HTTP. + * + * @param originalRepository + * @return true if external. + */ + static boolean isExternalHttpRepo( ArtifactRepository originalRepository ) + { + try + { + URL url = new URL( originalRepository.getUrl() ); + return ( "http".equalsIgnoreCase( url.getProtocol() ) || "dav".equalsIgnoreCase( url.getProtocol() ) + || "dav:http".equalsIgnoreCase( url.getProtocol() ) + || "dav+http".equalsIgnoreCase( url.getProtocol() ) ) && !isLocal( url.getHost() ); } catch ( MalformedURLException e ) { diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java index a4835fdd473b..996eb193dcf6 100644 --- a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java +++ b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java @@ -37,7 +37,7 @@ import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.classrealm.ClassRealmRequest.RealmType; -import org.apache.maven.extension.internal.CoreExportsProvider; +import org.apache.maven.extension.internal.CoreExports; import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; import org.codehaus.plexus.MutablePlexusContainer; @@ -92,20 +92,20 @@ public class DefaultClassRealmManager @Inject public DefaultClassRealmManager( Logger logger, PlexusContainer container, - List delegates, CoreExportsProvider exports ) + List delegates, CoreExports exports ) { this.logger = logger; this.world = ( (MutablePlexusContainer) container ).getClassWorld(); this.containerRealm = container.getContainerRealm(); this.delegates = delegates; - Map foreignImports = exports.get().getExportedPackages(); + Map foreignImports = exports.getExportedPackages(); this.mavenApiRealm = createRealm( API_REALMID, RealmType.Core, null /* parent */, null /* parentImports */, foreignImports, null /* artifacts */ ); - this.providedArtifacts = exports.get().getExportedArtifacts(); + this.providedArtifacts = exports.getExportedArtifacts(); } private ClassRealm newRealm( String id ) diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java b/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java index 5b56df36d003..98c5573c9736 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java +++ b/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java @@ -84,15 +84,9 @@ public void setProjects( List projects ) if ( !projects.isEmpty() ) { this.currentProject = projects.get( 0 ); - this.topLevelProject = currentProject; - for ( MavenProject project : projects ) - { - if ( project.isExecutionRoot() ) - { - topLevelProject = project; - break; - } - } + this.topLevelProject = + projects.stream().filter( project -> project.isExecutionRoot() ).findFirst() + .orElse( currentProject ); } else { diff --git a/maven-core/src/main/java/org/apache/maven/execution/infoproviders/DefaultPluginsMetadataInfoProvider.java b/maven-core/src/main/java/org/apache/maven/execution/infoproviders/DefaultPluginsMetadataInfoProvider.java new file mode 100644 index 000000000000..616a3a88a4bf --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/execution/infoproviders/DefaultPluginsMetadataInfoProvider.java @@ -0,0 +1,137 @@ +package org.apache.maven.execution.infoproviders; + +/* + * 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.Objects; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.apache.maven.artifact.repository.metadata.Metadata; +import org.apache.maven.artifact.repository.metadata.Plugin; +import org.apache.maven.artifact.repository.metadata.RepositoryMetadata; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; +import org.apache.maven.repository.internal.PluginsMetadataInfoProvider; +import org.apache.maven.repository.legacy.metadata.ArtifactMetadata; +import org.eclipse.aether.artifact.Artifact; + +import static java.util.Objects.requireNonNull; + +/** + * Default implementation of {@link PluginsMetadataInfoProvider}. + */ +@Named +@Singleton +public class DefaultPluginsMetadataInfoProvider + implements PluginsMetadataInfoProvider +{ + private final Provider mavenSessionProvider; + + @Inject + public DefaultPluginsMetadataInfoProvider( final Provider mavenSessionProvider ) + { + this.mavenSessionProvider = requireNonNull( mavenSessionProvider ); + } + + @Override + public PluginInfo getPluginInfo( final Artifact artifact ) + { + MavenSession mavenSession = mavenSessionProvider.get(); + if ( mavenSession != null ) + { + MavenProject mavenProject = searchForProject( mavenSession, artifact ); + if ( mavenProject != null && "maven-plugin".equals( mavenProject.getPackaging() ) ) + { + Plugin plugin = searchForPluginGroupLevelRepositoryMetadata( mavenProject ); + + if ( plugin != null ) + { + return new PluginInfo() + { + @Override + public String getPluginGroupId() + { + return artifact.getGroupId(); + } + + @Override + public String getPluginArtifactId() + { + return artifact.getArtifactId(); + } + + @Override + public String getPluginPrefix() + { + return plugin.getPrefix(); + } + + @Override + public String getPluginName() + { + return plugin.getName(); + } + }; + } + } + } + + return null; + } + + private MavenProject searchForProject( MavenSession mavenSession, Artifact artifact ) + { + for ( MavenProject mavenProject : mavenSession.getProjects() ) + { + if ( mavenProject.getArtifact() != null + && Objects.equals( mavenProject.getGroupId(), artifact.getGroupId() ) + && Objects.equals( mavenProject.getArtifactId(), artifact.getArtifactId() ) ) + { + return mavenProject; + } + } + return null; + } + + private Plugin searchForPluginGroupLevelRepositoryMetadata( MavenProject mavenProject ) + { + org.apache.maven.artifact.Artifact projectArtifact = mavenProject.getArtifact(); + for ( ArtifactMetadata artifactMetadata : projectArtifact.getMetadataList() ) + { + if ( artifactMetadata instanceof RepositoryMetadata ) + { + RepositoryMetadata repositoryMetadata = (RepositoryMetadata) artifactMetadata; + Metadata metadata = repositoryMetadata.getMetadata(); + + for ( Plugin plugin : metadata.getPlugins() ) + { + if ( Objects.equals( plugin.getArtifactId(), mavenProject.getArtifactId() ) ) + { + return plugin; + } + } + } + } + return null; + } +} diff --git a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java index 331617cfa232..b769c386788c 100644 --- a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java +++ b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java @@ -20,14 +20,16 @@ */ import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import org.codehaus.plexus.classworlds.realm.ClassRealm; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.toMap; + /** * Provides information about artifacts (identified by groupId:artifactId string key) and classpath elements exported by * Maven core itself and loaded Maven core extensions. @@ -47,13 +49,9 @@ public CoreExports( CoreExtensionEntry entry ) public CoreExports( ClassRealm realm, Set exportedArtifacts, Set exportedPackages ) { - Map packages = new LinkedHashMap<>(); - for ( String pkg : exportedPackages ) - { - packages.put( pkg, realm ); - } this.artifacts = Collections.unmodifiableSet( new HashSet<>( exportedArtifacts ) ); - this.packages = Collections.unmodifiableMap( new HashMap<>( packages ) ); + this.packages = exportedPackages.stream().collect( + collectingAndThen( toMap( identity(), v -> realm ), Collections::unmodifiableMap ) ); } /** diff --git a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java index 3e6f9f7b6710..b1a30fe3c3aa 100644 --- a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java +++ b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java @@ -19,34 +19,34 @@ * under the License. */ +import java.util.Objects; + import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Provider; import javax.inject.Singleton; import org.codehaus.plexus.PlexusContainer; -import org.eclipse.sisu.Nullable; /** * CoreExportsProvider */ @Named @Singleton -public class CoreExportsProvider +public class CoreExportsProvider implements Provider { private final CoreExports exports; @Inject - public CoreExportsProvider( PlexusContainer container, @Nullable CoreExports exports ) + public CoreExportsProvider( PlexusContainer container ) + { + this( new CoreExports( CoreExtensionEntry.discoverFrom( container.getContainerRealm() ) ) ); + } + + public CoreExportsProvider( CoreExports exports ) { - if ( exports == null ) - { - this.exports = new CoreExports( CoreExtensionEntry.discoverFrom( container.getContainerRealm() ) ); - } - else - { - this.exports = exports; - } + this.exports = Objects.requireNonNull( exports ); } public CoreExports get() diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java index e0067f1fe4ae..7804312c9f90 100644 --- a/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java +++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java @@ -22,8 +22,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -42,9 +45,13 @@ public class DefaultProjectDependencyGraph implements ProjectDependencyGraph { - private ProjectSorter sorter; + private final ProjectSorter sorter; - private List allProjects; + private final List allProjects; + + private final Map order; + + private final Map projects; /** * Creates a new project dependency graph based on the specified projects. @@ -59,6 +66,16 @@ public DefaultProjectDependencyGraph( Collection projects ) super(); this.allProjects = Collections.unmodifiableList( new ArrayList<>( projects ) ); this.sorter = new ProjectSorter( projects ); + List sorted = this.sorter.getSortedProjects(); + this.order = new HashMap<>( sorted.size() ); + this.projects = new HashMap<>( sorted.size() ); + int index = 0; + for ( MavenProject project : sorted ) + { + String id = ProjectSorter.getId( project ); + this.projects.put( id, project ); + this.order.put( project, index++ ); + } } /** @@ -78,6 +95,16 @@ public DefaultProjectDependencyGraph( final List allProjects, super(); this.allProjects = Collections.unmodifiableList( new ArrayList<>( allProjects ) ); this.sorter = new ProjectSorter( projects ); + List sorted = this.sorter.getSortedProjects(); + this.order = new HashMap<>( sorted.size() ); + this.projects = new HashMap<>( sorted.size() ); + int index = 0; + for ( MavenProject project : sorted ) + { + String id = ProjectSorter.getId( project ); + this.projects.put( id, project ); + this.order.put( project, index++ ); + } } /** @@ -140,15 +167,13 @@ private void getUpstreamProjects( String projectId, Collection projectId private List getSortedProjects( Set projectIds ) { List result = new ArrayList<>( projectIds.size() ); - - for ( MavenProject mavenProject : sorter.getSortedProjects() ) + for ( String projectId : projectIds ) { - if ( projectIds.contains( ProjectSorter.getId( mavenProject ) ) ) - { - result.add( mavenProject ); - } + result.add( projects.get( projectId ) ); } + Collections.sort( result, new MavenProjectComparator() ); + return result; } @@ -158,4 +183,12 @@ public String toString() return sorter.getSortedProjects().toString(); } + private class MavenProjectComparator implements Comparator + { + @Override + public int compare( MavenProject o1, MavenProject o2 ) + { + return order.get( o1 ) - order.get( o2 ); + } + } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java b/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java new file mode 100644 index 000000000000..da158295ba81 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java @@ -0,0 +1,91 @@ +package org.apache.maven.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 java.util.ArrayList; +import java.util.List; + +/** + * Helper class to format multiline messages to the console + */ +public class MultilineMessageHelper +{ + + private static final int DEFAULT_MAX_SIZE = 65; + private static final char BOX_CHAR = '*'; + + public static String separatorLine() + { + StringBuilder sb = new StringBuilder( DEFAULT_MAX_SIZE ); + repeat( sb, '*', DEFAULT_MAX_SIZE ); + return sb.toString(); + } + + public static List format( String... lines ) + { + int size = DEFAULT_MAX_SIZE; + int remainder = size - 4; // 4 chars = 2 box_char + 2 spaces + List result = new ArrayList<>(); + StringBuilder sb = new StringBuilder( size ); + // first line + sb.setLength( 0 ); + repeat( sb, BOX_CHAR, size ); + result.add( sb.toString() ); + // lines + for ( String line : lines ) + { + sb.setLength( 0 ); + String[] words = line.split( "\\s+" ); + for ( String word : words ) + { + if ( sb.length() >= remainder - word.length() - ( sb.length() > 0 ? 1 : 0 ) ) + { + repeat( sb, ' ', remainder - sb.length() ); + result.add( BOX_CHAR + " " + sb + " " + BOX_CHAR ); + sb.setLength( 0 ); + } + if ( sb.length() > 0 ) + { + sb.append( ' ' ); + } + sb.append( word ); + } + + while ( sb.length() < remainder ) + { + sb.append( ' ' ); + } + result.add( BOX_CHAR + " " + sb + " " + BOX_CHAR ); + } + // last line + sb.setLength( 0 ); + repeat( sb, BOX_CHAR, size ); + result.add( sb.toString() ); + return result; + } + + private static void repeat( StringBuilder sb, char c, int nb ) + { + for ( int i = 0; i < nb; i++ ) + { + sb.append( c ); + } + } +} 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 248a3b6dd120..f57ff4b9bd04 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; @@ -53,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 @@ -65,6 +63,42 @@ @Named public class DefaultRepositorySystemSessionFactory { + private static final String MAVEN_RESOLVER_TRANSPORT_KEY = "maven.resolver.transport"; + + private static final String MAVEN_RESOLVER_TRANSPORT_DEFAULT = "default"; + + private static final String MAVEN_RESOLVER_TRANSPORT_WAGON = "wagon"; + + private static final String MAVEN_RESOLVER_TRANSPORT_NATIVE = "native"; + + private static final String MAVEN_RESOLVER_TRANSPORT_AUTO = "auto"; + + private static final String WAGON_TRANSPORTER_PRIORITY_KEY = "aether.priority.WagonTransporterFactory"; + + private static final String NATIVE_HTTP_TRANSPORTER_PRIORITY_KEY = "aether.priority.HttpTransporterFactory"; + + private static final String NATIVE_FILE_TRANSPORTER_PRIORITY_KEY = "aether.priority.FileTransporterFactory"; + + private static final String RESOLVER_MAX_PRIORITY = String.valueOf( Float.MAX_VALUE ); + + private static final String MAVEN_RESOLVER_LOCKING_KEY = "maven.resolver.locking"; + + private static final String MAVEN_RESOLVER_LOCKING_DEFAULT = "default"; + + private static final String MAVEN_RESOLVER_LOCKING_LOCAL = "local"; + + private static final String MAVEN_RESOLVER_LOCKING_FILE = "file"; + + private static final String MAVEN_RESOLVER_LOCKING_HAZELCAST = "hazelcast"; + + private static final String MAVEN_RESOLVER_LOCKING_REDISSON = "redisson"; + + private static final String MAVEN_RESOLVER_LOCKING_AUTO = "auto"; + + private static final String MAVEN_RESOLVER_LOCKING_LOCK_FACTORY_KEY = "aether.syncContext.named.factory"; + + private static final String MAVEN_RESOLVER_LOCKING_NAME_MAPPER_KEY = "aether.syncContext.named.nameMapper"; + @Inject private Logger logger; @@ -93,6 +127,10 @@ public class DefaultRepositorySystemSessionFactory @Inject MavenRepositorySystem mavenRepositorySystem; + @Inject + private RuntimeInformation runtimeInformation; + + @SuppressWarnings( "checkstyle:methodlength" ) public DefaultRepositorySystemSession newRepositorySession( MavenExecutionRequest request ) { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); @@ -102,6 +140,7 @@ public DefaultRepositorySystemSession newRepositorySession( MavenExecutionReques Map configProps = new LinkedHashMap<>(); configProps.put( ConfigurationProperties.USER_AGENT, getUserAgent() ); configProps.put( ConfigurationProperties.INTERACTIVE, request.isInteractiveMode() ); + configProps.put( "maven.startTime", request.getStartTime() ); configProps.putAll( request.getSystemProperties() ); configProps.putAll( request.getUserProperties() ); @@ -177,8 +216,8 @@ else if ( request.isUpdateSnapshots() ) DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector(); for ( Mirror mirror : request.getMirrors() ) { - mirrorSelector.add( mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, mirror.getMirrorOf(), - mirror.getMirrorOfLayouts() ); + mirrorSelector.add( mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, mirror.isBlocked(), + mirror.getMirrorOf(), mirror.getMirrorOfLayouts() ); } session.setMirrorSelector( mirrorSelector ); @@ -222,6 +261,74 @@ else if ( request.isUpdateSnapshots() ) } session.setAuthenticationSelector( authSelector ); + Object transport = configProps.getOrDefault( MAVEN_RESOLVER_TRANSPORT_KEY, MAVEN_RESOLVER_TRANSPORT_DEFAULT ); + if ( MAVEN_RESOLVER_TRANSPORT_DEFAULT.equals( transport ) ) + { + // The "default" mode (user did not set anything) needs to tweak resolver default priorities + // that are coded like this (default values): + // + // org.eclipse.aether.transport.http.HttpTransporterFactory.priority = 5.0f; + // org.eclipse.aether.transport.wagon.WagonTransporterFactory.priority = -1.0f; + // + // Hence, as both are present on classpath, HttpTransport would be selected, while + // we want to retain "default" behaviour of Maven and use Wagon. To achieve that, + // we set explicitly priority of WagonTransport to 6.0f (just above of HttpTransport), + // to make it "win" over HttpTransport. We do this to NOT interfere with possibly + // installed OTHER transports and their priorities, as unlike "wagon" or "native" + // transport setting, that sets priorities to MAX, hence prevents any 3rd party + // transport to get into play (inhibits them), in default mode we want to retain + // old behavior. Also, this "default" mode is different from "auto" setting, + // as it does not alter resolver priorities at all, and uses priorities as is. + + configProps.put( WAGON_TRANSPORTER_PRIORITY_KEY, "6" ); + } + else if ( MAVEN_RESOLVER_TRANSPORT_NATIVE.equals( transport ) ) + { + // Make sure (whatever extra priority is set) that resolver native is selected + configProps.put( NATIVE_FILE_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY ); + configProps.put( NATIVE_HTTP_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY ); + } + else if ( MAVEN_RESOLVER_TRANSPORT_WAGON.equals( transport ) ) + { + // Make sure (whatever extra priority is set) that wagon is selected + configProps.put( WAGON_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY ); + } + else if ( !MAVEN_RESOLVER_TRANSPORT_AUTO.equals( transport ) ) + { + throw new IllegalArgumentException( "Unknown resolver transport '" + transport + + "'. Supported transports are: " + MAVEN_RESOLVER_TRANSPORT_WAGON + ", " + + MAVEN_RESOLVER_TRANSPORT_NATIVE + ", " + MAVEN_RESOLVER_TRANSPORT_AUTO ); + } + + Object locking = configProps.getOrDefault( MAVEN_RESOLVER_LOCKING_KEY, MAVEN_RESOLVER_LOCKING_DEFAULT ); + if ( MAVEN_RESOLVER_LOCKING_DEFAULT.equals( locking ) || MAVEN_RESOLVER_LOCKING_FILE.equals( locking ) ) + { + // The "default" mode (user did not set anything) is same as "file" mode + configProps.put( MAVEN_RESOLVER_LOCKING_LOCK_FACTORY_KEY, "file-lock" ); + configProps.put( MAVEN_RESOLVER_LOCKING_NAME_MAPPER_KEY, "file-gav" ); + } + else if ( MAVEN_RESOLVER_LOCKING_LOCAL.equals( locking ) ) + { + configProps.put( MAVEN_RESOLVER_LOCKING_LOCK_FACTORY_KEY, "rwlock-local" ); + configProps.put( MAVEN_RESOLVER_LOCKING_NAME_MAPPER_KEY, "gav" ); + } + else if ( MAVEN_RESOLVER_LOCKING_HAZELCAST.equals( locking ) ) + { + configProps.put( MAVEN_RESOLVER_LOCKING_LOCK_FACTORY_KEY, "semaphore-hazelcast-client" ); + configProps.put( MAVEN_RESOLVER_LOCKING_NAME_MAPPER_KEY, "discriminating" ); + } + else if ( MAVEN_RESOLVER_LOCKING_REDISSON.equals( locking ) ) + { + configProps.put( MAVEN_RESOLVER_LOCKING_LOCK_FACTORY_KEY, "rwlock-redisson" ); + configProps.put( MAVEN_RESOLVER_LOCKING_NAME_MAPPER_KEY, "discriminating" ); + } + else if ( !MAVEN_RESOLVER_LOCKING_AUTO.equals( locking ) ) + { + throw new IllegalArgumentException( "Unknown resolver locking mode '" + transport + + "'. Supported locking modes are: " + MAVEN_RESOLVER_LOCKING_FILE + ", " + + MAVEN_RESOLVER_LOCKING_LOCAL + ", " + MAVEN_RESOLVER_LOCKING_AUTO ); + } + session.setTransferListener( request.getTransferListener() ); session.setRepositoryListener( eventSpyDispatcher.chainListener( new LoggingRepositoryListener( logger ) ) ); @@ -243,28 +350,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" ); - } - } diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/MavenChainedWorkspaceReader.java b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenChainedWorkspaceReader.java new file mode 100644 index 000000000000..4bc16a9271c8 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenChainedWorkspaceReader.java @@ -0,0 +1,106 @@ +package org.apache.maven.internal.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.util.Collection; +import java.util.List; + +import org.apache.maven.model.Model; +import org.apache.maven.repository.internal.MavenWorkspaceReader; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.repository.WorkspaceRepository; +import org.eclipse.aether.util.repository.ChainedWorkspaceReader; + +/** + * A maven workspace reader that delegates to a chain of other readers, effectively aggregating their contents. + */ +public final class MavenChainedWorkspaceReader + implements MavenWorkspaceReader +{ + + private ChainedWorkspaceReader delegate; + + private WorkspaceReader[] readers; + + /** + * Creates a new workspace reader by chaining the specified readers. + * + * @param readers The readers to chain must not be {@code null}. + */ + private MavenChainedWorkspaceReader( WorkspaceReader... readers ) + { + this.delegate = new ChainedWorkspaceReader( readers ); + this.readers = readers; + } + + @Override + public Model findModel( Artifact artifact ) + { + for ( WorkspaceReader workspaceReader : readers ) + { + if ( workspaceReader instanceof MavenWorkspaceReader ) + { + Model model = ( (MavenWorkspaceReader) workspaceReader ).findModel( artifact ); + if ( model != null ) + { + return model; + } + } + } + return null; + } + + @Override + public WorkspaceRepository getRepository() + { + return delegate.getRepository(); + } + + @Override + public File findArtifact( Artifact artifact ) + { + return delegate.findArtifact( artifact ); + } + + @Override + public List findVersions( Artifact artifact ) + { + return delegate.findVersions( artifact ); + } + + /** + * chains a collection of {@link WorkspaceReader}s + * @param workspaceReaderCollection the collection of readers, might be empty but never null + * @return if the collection contains only one item returns the single item, otherwise creates a new + * {@link MavenChainedWorkspaceReader} chaining all readers in the order of the given collection. + */ + public static WorkspaceReader of( Collection workspaceReaderCollection ) + { + WorkspaceReader[] readers = workspaceReaderCollection.toArray( new WorkspaceReader[0] ); + if ( readers.length == 1 ) + { + return readers[0]; + } + return new MavenChainedWorkspaceReader( readers ); + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java index a7d9facb2e90..1a13365c8c0b 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java @@ -43,7 +43,7 @@ @Component( role = DefaultLifecycles.class ) public class DefaultLifecycles { - public static final String[] STANDARD_LIFECYCLES = { "default", "clean", "site" }; + public static final String[] STANDARD_LIFECYCLES = { "clean", "default", "site" }; // @Configuration(source="org/apache/maven/lifecycle/lifecycles.xml") @@ -108,6 +108,9 @@ public Map getPhaseToLifecycleMap() return phaseToLifecycleMap; } + /** + * Returns an ordered list of lifecycles + */ public List getLifeCycles() { // ensure canonical order of standard lifecycles 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 getPluginsBoundByDefaultToAllLifecycles( String packaging ) Map plugins = new LinkedHashMap<>(); - for ( Lifecycle lifecycle : getOrderedLifecycles() ) + for ( Lifecycle lifecycle : defaultLifeCycles.getLifeCycles() ) { org.apache.maven.lifecycle.mapping.Lifecycle lifecycleConfiguration = lifecycleMappingForPackaging.getLifecycles().get( lifecycle.getId() ); @@ -131,25 +128,6 @@ else if ( lifecycle.getDefaultLifecyclePhases() != null ) return plugins.keySet(); } - private List getOrderedLifecycles() - { - // NOTE: The lifecycle order can affect implied execution ids so we better be deterministic. - - List lifecycles = new ArrayList<>( defaultLifeCycles.getLifeCycles() ); - - Collections.sort( lifecycles, new Comparator() - { - - public int compare( Lifecycle l1, Lifecycle l2 ) - { - return l1.getId().compareTo( l2.getId() ); - } - - } ); - - return lifecycles; - } - private void parseLifecyclePhaseDefinitions( Map plugins, String phase, LifecyclePhase goals ) { String modelId = "org.apache.maven:maven-core:" + this.getClass().getPackage().getImplementationVersion() 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..e655360d353b 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 @@ -20,15 +20,29 @@ */ import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.maven.lifecycle.MojoExecutionConfigurator; import org.apache.maven.model.Plugin; import org.apache.maven.model.PluginExecution; import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.plugin.descriptor.MojoDescriptor; +import org.apache.maven.plugin.descriptor.Parameter; +import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.component.annotations.Component; +import org.apache.maven.shared.utils.logging.MessageBuilder; +import org.apache.maven.shared.utils.logging.MessageUtils; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.util.Arrays.stream; /** * @since 3.3.1, MNG-5753 @@ -37,13 +51,14 @@ public class DefaultMojoExecutionConfigurator implements MojoExecutionConfigurator { + private final Logger logger = LoggerFactory.getLogger( getClass() ); @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() ); @@ -73,6 +88,8 @@ else if ( allowPluginLevelConfig ) mojoConfiguration = Xpp3Dom.mergeXpp3Dom( mojoExecution.getConfiguration(), mojoConfiguration ); mojoExecution.setConfiguration( mojoConfiguration ); + + checkUnknownMojoConfigurationParameters( mojoExecution ); } } @@ -105,4 +122,91 @@ private PluginExecution findPluginExecution( String executionId, Collection parametersNamesGoal = Optional.ofNullable( mojoDescriptor.getParameters() ) + .orElseGet( Collections::emptyList ).stream() + .flatMap( this::getParameterNames ) + .collect( Collectors.toSet() ); + + Set unknownParameters = getUnknownParameters( mojoExecution, parametersNamesGoal ); + + if ( unknownParameters.isEmpty() ) + { + return; + } + + // second step get parameter names of all plugin goals + Set parametersNamesAll = Optional.ofNullable( mojoDescriptor.getPluginDescriptor() ) + .map( PluginDescriptor::getMojos ) + .orElseGet( Collections::emptyList ).stream() + .filter( m -> m.getParameters() != null ) + .flatMap( m -> m.getParameters().stream() ) + .flatMap( this::getParameterNames ) + .collect( Collectors.toSet() ); + + unknownParameters = getUnknownParameters( mojoExecution, parametersNamesAll ); + + unknownParameters.stream() + .filter( parameterName -> isNotReportPluginsForMavenSite( parameterName, mojoExecution ) ) + .forEach( + name -> + { + MessageBuilder messageBuilder = MessageUtils.buffer() + .warning( "Parameter '" ) + .warning( name ) + .warning( "' is unknown for plugin '" ) + .warning( mojoExecution.getArtifactId() ).warning( ":" ) + .warning( mojoExecution.getVersion() ).warning( ":" ) + .warning( mojoExecution.getGoal() ); + + if ( mojoExecution.getExecutionId() != null ) + { + messageBuilder.warning( " (" ); + messageBuilder.warning( mojoExecution.getExecutionId() ); + messageBuilder.warning( ")" ); + } + + messageBuilder.warning( "'" ); + + logger.warn( messageBuilder.toString() ); + } ); + } + + private boolean isNotReportPluginsForMavenSite( String parameterName, + MojoExecution mojoExecution ) + { + return !( "reportPlugins".equals( parameterName ) + && "maven-site-plugin".equals( mojoExecution.getArtifactId() ) ); + } + + private Stream getParameterNames( Parameter parameter ) + { + if ( parameter.getAlias() != null ) + { + return Stream.of( parameter.getName(), parameter.getAlias() ); + } + else + { + return Stream.of( parameter.getName() ); + } + } + + private Set getUnknownParameters( MojoExecution mojoExecution, Set parameters ) + { + return stream( mojoExecution.getConfiguration().getChildren() ) + .map( Xpp3Dom::getName ) + .filter( name -> !parameters.contains( name ) ) + .collect( Collectors.toSet() ); + } + } 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..c3117cf4fa12 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 @@ -24,21 +24,29 @@ import org.apache.maven.artifact.resolver.filter.CumulativeScopeArtifactFilter; import org.apache.maven.execution.ExecutionEvent; import org.apache.maven.execution.MavenSession; +import org.apache.maven.internal.MultilineMessageHelper; import org.apache.maven.lifecycle.LifecycleExecutionException; import org.apache.maven.lifecycle.MissingProjectException; import org.apache.maven.plugin.BuildPluginManager; import org.apache.maven.plugin.MavenPluginManager; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoExecutionRunner; +import org.apache.maven.plugin.MojosExecutionStrategy; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.PluginConfigurationException; import org.apache.maven.plugin.PluginIncompatibleException; import org.apache.maven.plugin.PluginManagerException; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.util.StringUtils; +import org.eclipse.aether.SessionData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Arrays; @@ -48,6 +56,11 @@ 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.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** *

    @@ -64,6 +77,8 @@ public class MojoExecutor { + private static final Logger LOGGER = LoggerFactory.getLogger( MojoExecutor.class ); + @Requirement private BuildPluginManager pluginManager; @@ -76,6 +91,13 @@ public class MojoExecutor @Requirement private ExecutionEventCatapult eventCatapult; + private final OwnerReentrantReadWriteLock aggregatorLock = new OwnerReentrantReadWriteLock(); + + @Requirement + private PlexusContainer container; + + private final Map mojos = new ConcurrentHashMap<>(); + public MojoExecutor() { } @@ -135,21 +157,36 @@ else if ( Artifact.SCOPE_TEST.equals( classpath ) ) return Collections.unmodifiableCollection( scopes ); } - public void execute( MavenSession session, List mojoExecutions, ProjectIndex projectIndex ) + public void execute( final MavenSession session, + final List mojoExecutions, + final ProjectIndex projectIndex ) throws LifecycleExecutionException { - DependencyContext dependencyContext = newDependencyContext( session, mojoExecutions ); + final DependencyContext dependencyContext = newDependencyContext( session, mojoExecutions ); - PhaseRecorder phaseRecorder = new PhaseRecorder( session.getCurrentProject() ); + final PhaseRecorder phaseRecorder = new PhaseRecorder( session.getCurrentProject() ); - for ( MojoExecution mojoExecution : mojoExecutions ) + MojosExecutionStrategy strategy; + try + { + strategy = container.lookup( MojosExecutionStrategy.class ); + } + catch ( ComponentLookupException e ) { - execute( session, mojoExecution, projectIndex, dependencyContext, phaseRecorder ); + throw new IllegalStateException( "Unable to lookup MojosExecutionStrategy", e ); } + strategy.execute( mojoExecutions, session, new MojoExecutionRunner() + { + @Override + public void run( MojoExecution mojoExecution ) throws LifecycleExecutionException + { + MojoExecutor.this.execute( session, mojoExecution, projectIndex, dependencyContext, phaseRecorder ); + } + } ); } - public void execute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex, + private void execute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex, DependencyContext dependencyContext, PhaseRecorder phaseRecorder ) throws LifecycleExecutionException { @@ -197,12 +234,157 @@ private void execute( MavenSession session, MojoExecution mojoExecution, Project } } + 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 class ProjectLock implements AutoCloseable + { + final Lock acquiredAggregatorLock; + final OwnerReentrantLock acquiredProjectLock; + + ProjectLock( MavenSession session, MojoDescriptor mojoDescriptor ) + { + mojos.put( Thread.currentThread(), mojoDescriptor ); + if ( session.getRequest().getDegreeOfConcurrency() > 1 ) + { + boolean aggregator = mojoDescriptor.isAggregator(); + acquiredAggregatorLock = aggregator ? aggregatorLock.writeLock() : aggregatorLock.readLock(); + acquiredProjectLock = getProjectLock( session ); + if ( !acquiredAggregatorLock.tryLock() ) + { + Thread owner = aggregatorLock.getOwner(); + MojoDescriptor ownerMojo = owner != null ? mojos.get( owner ) : null; + String str = ownerMojo != null ? " The " + ownerMojo.getId() : "An"; + String msg = str + " aggregator mojo is already being executed " + + "in this parallel build, those kind of mojos require exclusive access to " + + "reactor to prevent race conditions. This mojo execution will be blocked " + + "until the aggregator mojo is done."; + warn( msg ); + acquiredAggregatorLock.lock(); + } + if ( !acquiredProjectLock.tryLock() ) + { + Thread owner = acquiredProjectLock.getOwner(); + MojoDescriptor ownerMojo = owner != null ? mojos.get( owner ) : null; + String str = ownerMojo != null ? " The " + ownerMojo.getId() : "A"; + String msg = str + " mojo is already being executed " + + "on the project " + session.getCurrentProject().getGroupId() + + ":" + session.getCurrentProject().getArtifactId() + ". " + + "This mojo execution will be blocked " + + "until the mojo is done."; + warn( msg ); + 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(); + } + mojos.remove( Thread.currentThread() ); + } + + @SuppressWarnings( { "unchecked", "rawtypes" } ) + private OwnerReentrantLock 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 ); + } + OwnerReentrantLock acquiredProjectLock = locks.get( session.getCurrentProject() ); + if ( acquiredProjectLock == null ) + { + acquiredProjectLock = new OwnerReentrantLock(); + OwnerReentrantLock prev = locks.putIfAbsent( session.getCurrentProject(), acquiredProjectLock ); + if ( prev != null ) + { + acquiredProjectLock = prev; + } + } + return acquiredProjectLock; + } + } + + static class OwnerReentrantLock extends ReentrantLock + { + @Override + public Thread getOwner() + { + return super.getOwner(); + } + } + + static class OwnerReentrantReadWriteLock extends ReentrantReadWriteLock + { + @Override + public Thread getOwner() + { + return super.getOwner(); + } + } + + private static void warn( String msg ) + { + for ( String s : MultilineMessageHelper.format( msg ) ) + { + LOGGER.warn( s ); + } + } + + 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 ); - eventCatapult.fire( ExecutionEvent.Type.MojoStarted, session, mojoExecution ); + try ( ProjectLock lock = new ProjectLock( session, mojoDescriptor ) ) + { + doExecute2( session, mojoExecution ); + } + finally + { + for ( MavenProject forkedProject : forkedProjects ) + { + forkedProject.setExecutionProject( null ); + } + } + } + private void doExecute2( MavenSession session, MojoExecution mojoExecution ) + throws LifecycleExecutionException + { + eventCatapult.fire( ExecutionEvent.Type.MojoStarted, session, mojoExecution ); try { try @@ -223,13 +405,6 @@ private void execute( MavenSession session, MojoExecution mojoExecution, Project throw e; } - finally - { - for ( MavenProject forkedProject : forkedProjects ) - { - forkedProject.setExecutionProject( null ); - } - } } public void ensureDependenciesAreResolved( MojoDescriptor mojoDescriptor, MavenSession session, 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..4ee7be5241a4 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 @@ -24,6 +24,7 @@ import org.apache.maven.execution.ExecutionEvent; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenSession; +import org.apache.maven.internal.MultilineMessageHelper; import org.apache.maven.lifecycle.LifecycleExecutionException; import org.apache.maven.lifecycle.LifecycleNotFoundException; import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException; @@ -98,39 +99,40 @@ 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() ) { - logger.warn( "*****************************************************************" ); - logger.warn( "* Your build is requesting parallel execution, but project *" ); - logger.warn( "* contains the following plugin(s) that have goals not marked *" ); - logger.warn( "* as @threadSafe to support parallel building. *" ); - logger.warn( "* While this /may/ work fine, please look for plugin updates *" ); - logger.warn( "* and/or request plugins be made thread-safe. *" ); - logger.warn( "* If reporting an issue, report it against the plugin in *" ); - logger.warn( "* question, not against maven-core *" ); - logger.warn( "*****************************************************************" ); + for ( String s : MultilineMessageHelper.format( + "Your build is requesting parallel execution, but this project contains the following " + + "plugin(s) that have goals not marked as thread-safe to support parallel execution.", + "While this /may/ work fine, please look for plugin updates and/or " + + "request plugins be made thread-safe.", + "If reporting an issue, report it against the plugin in question, not against Apache Maven." ) ) + { + logger.warn( s ); + } if ( logger.isDebugEnabled() ) { final Set unsafeGoals = executionPlan.getNonThreadSafeMojos(); - logger.warn( "The following goals are not marked @threadSafe in " + project.getName() + ":" ); + logger.warn( "The following goals are not marked as thread-safe in " + project.getName() + ":" ); for ( MojoDescriptor unsafeGoal : unsafeGoals ) { - logger.warn( unsafeGoal.getId() ); + logger.warn( " " + unsafeGoal.getId() ); } } else { - logger.warn( "The following plugins are not marked @threadSafe in " + project.getName() + ":" ); + logger.warn( "The following plugins are not marked as thread-safe in " + project.getName() + ":" ); for ( Plugin unsafePlugin : unsafePlugins ) { - logger.warn( unsafePlugin.getId() ); + logger.warn( " " + unsafePlugin.getId() ); } - logger.warn( "Enable debug to see more precisely which goals are not marked @threadSafe." ); + logger.warn( "" ); + logger.warn( "Enable debug to see precisely which goals are not marked as thread-safe." ); } - logger.warn( "*****************************************************************" ); + logger.warn( MultilineMessageHelper.separatorLine() ); } } 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 94d10af4b44c..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,19 +187,51 @@ 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() { public ProjectSegment call() { - // muxer.associateThreadWithProjectSegment( projectBuild ); - lifecycleModuleBuilder.buildProject( projectBuild.getSession(), rootSession, reactorContext, - projectBuild.getProject(), taskSegment ); - // muxer.setThisModuleComplete( projectBuild ); + final Thread currentThread = Thread.currentThread(); + final String originalThreadName = currentThread.getName(); + 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, + project, taskSegment ); + // muxer.setThisModuleComplete( projectBuild ); - return projectBuild; + return projectBuild; + } + finally + { + currentThread.setName( originalThreadName ); + } } }; } + + 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; + } } diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping.java b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping.java index e12debef5fce..283a179d2530 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping.java @@ -19,10 +19,14 @@ * under the License. */ +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; + /** * DefaultLifecycleMapping */ @@ -38,7 +42,28 @@ public class DefaultLifecycleMapping private Map phases; /** - * Populates the lifecycle map from the injected list of lifecycle mappings (if not already done). + * Default ctor for plexus compatibility: lifecycles are most commonly defined in Plexus XML, that does field + * injection. Still, for Plexus to be able to instantiate this class, default ctor is needed. + * + * @deprecated Should not be used in Java code. + */ + @Deprecated + public DefaultLifecycleMapping() + { + } + + /** + * Ctor to be used in Java code/providers. + */ + public DefaultLifecycleMapping( final List lifecycles ) + { + this.lifecycleMap = Collections.unmodifiableMap( + lifecycles.stream().collect( toMap( Lifecycle::getId, identity() ) ) + ); + } + + /** + * Plexus: Populates the lifecycle map from the injected list of lifecycle mappings (if not already done). */ private void initLifecycleMap() { @@ -79,6 +104,7 @@ private void initLifecycleMap() } } + @Override public Map getLifecycles() { initLifecycleMap(); @@ -86,6 +112,8 @@ public Map getLifecycles() return lifecycleMap; } + @Deprecated + @Override public List getOptionalMojos( String lifecycle ) { return null; @@ -110,7 +138,7 @@ else if ( "default".equals( lifecycle ) ) return null; } } - + @Deprecated public Map getPhases( String lifecycle ) { diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultMojosExecutionStrategy.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultMojosExecutionStrategy.java new file mode 100644 index 000000000000..9507c7ad17c0 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultMojosExecutionStrategy.java @@ -0,0 +1,46 @@ +package org.apache.maven.plugin; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.lifecycle.LifecycleExecutionException; + +import javax.inject.Named; +import javax.inject.Singleton; +import java.util.List; + +/** + * Default mojo execution strategy. It just iterates over mojo executions and runs one by one + */ +@Named +@Singleton +public class DefaultMojosExecutionStrategy implements MojosExecutionStrategy +{ + @Override + public void execute( List mojos, MavenSession session, MojoExecutionRunner mojoRunner ) + throws LifecycleExecutionException + { + for ( MojoExecution mojoExecution : mojos ) + { + mojoRunner.run( mojoExecution ); + } + + } +} diff --git a/maven-core/src/main/java/org/apache/maven/plugin/MojoExecutionRunner.java b/maven-core/src/main/java/org/apache/maven/plugin/MojoExecutionRunner.java new file mode 100644 index 000000000000..314e041a71b2 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/plugin/MojoExecutionRunner.java @@ -0,0 +1,36 @@ +package org.apache.maven.plugin; + +/* + * 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.lifecycle.LifecycleExecutionException; + +/** + * Provides context for mojo execution. Invocation of #run will result in actual execution + */ +public interface MojoExecutionRunner +{ + /** + * Runs mojo execution + * + * @param execution mojo execution + * @throws LifecycleExecutionException + */ + void run( MojoExecution execution ) throws LifecycleExecutionException; +} diff --git a/maven-core/src/main/java/org/apache/maven/plugin/MojosExecutionStrategy.java b/maven-core/src/main/java/org/apache/maven/plugin/MojosExecutionStrategy.java new file mode 100644 index 000000000000..e4babf68d7db --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/plugin/MojosExecutionStrategy.java @@ -0,0 +1,45 @@ +package org.apache.maven.plugin; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.lifecycle.LifecycleExecutionException; + +import java.util.List; + +/** + * Interface allows overriding default mojo execution strategy For example it is possible wrap some mojo execution to + * decorate default functionality or skip some executions + */ +public interface MojosExecutionStrategy +{ + + /** + * Entry point to the execution strategy + * + * @param mojos list of mojos representing a project build + * @param session current session + * @param mojoExecutionRunner mojo execution task which must be invoked by a strategy to actually run it + * @throws LifecycleExecutionException + */ + void execute( List mojos, MavenSession session, MojoExecutionRunner mojoExecutionRunner ) + throws LifecycleExecutionException; + +} diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginParametersValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginParametersValidator.java new file mode 100644 index 000000000000..3fe62a894f9c --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginParametersValidator.java @@ -0,0 +1,153 @@ +package org.apache.maven.plugin.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 java.util.Arrays; +import java.util.List; + +import org.apache.maven.plugin.descriptor.Parameter; +import org.apache.maven.shared.utils.logging.MessageBuilder; +import org.apache.maven.shared.utils.logging.MessageUtils; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; +import org.codehaus.plexus.configuration.PlexusConfiguration; +import org.slf4j.Logger; + +/** + * Common implementations for plugin parameters configuration validation. + * + * @author Slawomir Jaranowski + */ +abstract class AbstractMavenPluginParametersValidator implements MavenPluginConfigurationValidator +{ + + // plugin author can provide @Parameter( property = "session" ) in this case property will always evaluate + // so, we need ignore those + + // source org.apache.maven.plugin.PluginParameterExpressionEvaluator + private static final List IGNORED_PROPERTY_VALUES = Arrays.asList( + "basedir", + "executedProject", + "localRepository", + "mojo", + "mojoExecution", + "plugin", + "project", + "reactorProjects", + "session", + "settings" + ); + + private static final List IGNORED_PROPERTY_PREFIX = Arrays.asList( + "mojo.", + "pom.", + "plugin.", + "project.", + "session.", + "settings." + ); + + protected abstract Logger getLogger(); + + protected static boolean isValueSet( PlexusConfiguration config, + ExpressionEvaluator expressionEvaluator ) + { + if ( config == null ) + { + return false; + } + + // there are sub items ... so configuration is declared + if ( config.getChildCount() > 0 ) + { + return true; + } + + String strValue = config.getValue(); + + if ( strValue == null || strValue.isEmpty() ) + { + return false; + } + + if ( isIgnoredProperty( strValue ) ) + { + return false; + } + + // for declaration like @Parameter( property = "config.property" ) + // the value will contain ${config.property} + + try + { + return expressionEvaluator.evaluate( strValue ) != null; + } + catch ( ExpressionEvaluationException e ) + { + // not important + // will be reported during Mojo fields populate + } + + // fallback - in case of error in expressionEvaluator + return false; + } + + private static boolean isIgnoredProperty( String strValue ) + { + if ( !strValue.startsWith( "${" ) ) + { + return false; + } + + String propertyName = strValue.replace( "${", "" ).replace( "}", "" ); + + if ( IGNORED_PROPERTY_VALUES.contains( propertyName ) ) + { + return true; + } + + return IGNORED_PROPERTY_PREFIX.stream().anyMatch( propertyName::startsWith ); + } + + protected abstract String getParameterLogReason( Parameter parameter ); + + protected void logParameter( Parameter parameter ) + { + MessageBuilder messageBuilder = MessageUtils.buffer() + .warning( "Parameter '" ) + .warning( parameter.getName() ) + .warning( '\'' ); + + if ( parameter.getExpression() != null ) + { + String userProperty = parameter.getExpression().replace( "${", "'" ).replace( '}', '\'' ); + messageBuilder + .warning( " (user property " ) + .warning( userProperty ) + .warning( ")" ); + } + + messageBuilder + .warning( " " ) + .warning( getParameterLogReason( parameter ) ); + + getLogger().warn( messageBuilder.toString() ); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java index 86304714df1c..a69c88eac614 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java @@ -126,7 +126,7 @@ public class DefaultMavenPluginManager * same class realm is used to load build extensions and load mojos for extensions=true plugins. *

    * Note: This is part of internal implementation and may be changed or removed without notice - * + * * @since 3.3.0 */ public static final String KEY_EXTENSIONS_REALMS = DefaultMavenPluginManager.class.getName() + "/extensionsRealms"; @@ -164,6 +164,9 @@ public class DefaultMavenPluginManager @Requirement private PluginArtifactsCache pluginArtifactsCache; + @Requirement + private List configurationValidators; + private ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder(); private PluginDescriptorBuilder builder = new PluginDescriptorBuilder(); @@ -498,9 +501,24 @@ public T getConfiguredMojo( Class mojoInterface, MavenSession session, Mo ClassRealm pluginRealm = pluginDescriptor.getClassRealm(); + if ( pluginRealm == null ) + { + try + { + setupPluginRealm( pluginDescriptor, session, null, null, null ); + } + catch ( PluginResolutionException e ) + { + String msg = "Cannot setup plugin realm [mojoDescriptor=" + mojoDescriptor.getId() + + ", pluginDescriptor=" + pluginDescriptor.getId() + "]"; + throw new PluginConfigurationException( pluginDescriptor, msg, e ); + } + pluginRealm = pluginDescriptor.getClassRealm(); + } + if ( logger.isDebugEnabled() ) { - logger.debug( "Configuring mojo " + mojoDescriptor.getId() + " from plugin realm " + pluginRealm ); + logger.debug( "Loading mojo " + mojoDescriptor.getId() + " from plugin realm " + pluginRealm ); } // We are forcing the use of the plugin realm for all lookups that might occur during @@ -594,7 +612,13 @@ else if ( cause instanceof LinkageError ) ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator( session, mojoExecution ); - populatePluginFields( mojo, mojoDescriptor, pluginRealm, pomConfiguration, expressionEvaluator ); + for ( MavenPluginConfigurationValidator validator: configurationValidators ) + { + validator.validate( mojoDescriptor, pomConfiguration, expressionEvaluator ); + } + + populateMojoExecutionFields( mojo, mojoExecution.getExecutionId(), mojoDescriptor, pluginRealm, + pomConfiguration, expressionEvaluator ); return mojo; } @@ -605,8 +629,9 @@ else if ( cause instanceof LinkageError ) } } - private void populatePluginFields( Object mojo, MojoDescriptor mojoDescriptor, ClassRealm pluginRealm, - PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator ) + private void populateMojoExecutionFields( Object mojo, String executionId, MojoDescriptor mojoDescriptor, + ClassRealm pluginRealm, PlexusConfiguration configuration, + ExpressionEvaluator expressionEvaluator ) throws PluginConfigurationException { ComponentConfigurator configurator = null; @@ -629,8 +654,8 @@ private void populatePluginFields( Object mojo, MojoDescriptor mojoDescriptor, C ValidatingConfigurationListener validator = new ValidatingConfigurationListener( mojo, mojoDescriptor, listener ); - logger.debug( - "Configuring mojo '" + mojoDescriptor.getId() + "' with " + configuratorId + " configurator -->" ); + logger.debug( "Configuring mojo execution '" + mojoDescriptor.getId() + ':' + executionId + "' with " + + configuratorId + " configurator -->" ); configurator.configureComponent( mojo, configuration, expressionEvaluator, pluginRealm, validator ); 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 808c09d9ad7b..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 @@ -23,6 +23,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import org.apache.maven.RepositoryUtils; import org.apache.maven.model.Dependency; @@ -107,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 ) { @@ -258,7 +271,7 @@ public boolean visitEnter( DependencyNode node ) { final String premanagedScope = DependencyManagerUtils.getPremanagedScope( node ); buffer.append( " (scope managed from " ); - buffer.append( StringUtils.defaultString( premanagedScope, "default" ) ); + buffer.append( Objects.toString( premanagedScope, "default" ) ); buffer.append( ')' ); } @@ -266,7 +279,7 @@ public boolean visitEnter( DependencyNode node ) { final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node ); buffer.append( " (version managed from " ); - buffer.append( StringUtils.defaultString( premanagedVersion, "default" ) ); + buffer.append( Objects.toString( premanagedVersion, "default" ) ); buffer.append( ')' ); } @@ -274,7 +287,7 @@ public boolean visitEnter( DependencyNode node ) { final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional( node ); buffer.append( " (optionality managed from " ); - buffer.append( StringUtils.defaultString( premanagedOptional, "default" ) ); + buffer.append( Objects.toString( premanagedOptional, "default" ) ); buffer.append( ')' ); } @@ -285,7 +298,7 @@ public boolean visitEnter( DependencyNode node ) DependencyManagerUtils.getPremanagedExclusions( node ); buffer.append( " (exclusions managed from " ); - buffer.append( StringUtils.defaultString( premanagedExclusions, "default" ) ); + buffer.append( Objects.toString( premanagedExclusions, "default" ) ); buffer.append( ')' ); } @@ -296,7 +309,7 @@ public boolean visitEnter( DependencyNode node ) DependencyManagerUtils.getPremanagedProperties( node ); buffer.append( " (properties managed from " ); - buffer.append( StringUtils.defaultString( premanagedProperties, "default" ) ); + buffer.append( Objects.toString( premanagedProperties, "default" ) ); buffer.append( ')' ); } } diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java new file mode 100644 index 000000000000..5f4af1a9c7e3 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java @@ -0,0 +1,103 @@ +package org.apache.maven.plugin.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.plugin.descriptor.MojoDescriptor; +import org.apache.maven.plugin.descriptor.Parameter; +import org.apache.maven.shared.utils.logging.MessageUtils; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; +import org.codehaus.plexus.configuration.PlexusConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Print warnings if deprecated mojo or parameters of plugin are used in configuration. + * + * @author Slawomir Jaranowski + */ + +@Component( role = MavenPluginConfigurationValidator.class ) +class DeprecatedPluginValidator extends AbstractMavenPluginParametersValidator +{ + private static final Logger LOGGER = LoggerFactory.getLogger( DeprecatedPluginValidator.class ); + + @Override + protected Logger getLogger() + { + return LOGGER; + } + + @Override + protected String getParameterLogReason( Parameter parameter ) + { + return "is deprecated: " + parameter.getDeprecated(); + } + + @Override + public void validate( MojoDescriptor mojoDescriptor, + PlexusConfiguration pomConfiguration, + ExpressionEvaluator expressionEvaluator ) + { + if ( !LOGGER.isWarnEnabled() ) + { + return; + } + + if ( mojoDescriptor.getDeprecated() != null ) + { + logDeprecatedMojo( mojoDescriptor ); + } + + if ( mojoDescriptor.getParameters() == null ) + { + return; + } + + mojoDescriptor.getParameters().stream() + .filter( parameter -> parameter.getDeprecated() != null ) + .filter( Parameter::isEditable ) + .forEach( parameter -> checkParameter( parameter, pomConfiguration, expressionEvaluator ) ); + } + + private void checkParameter( Parameter parameter, + PlexusConfiguration pomConfiguration, + ExpressionEvaluator expressionEvaluator ) + { + PlexusConfiguration config = pomConfiguration.getChild( parameter.getName(), false ); + + if ( isValueSet( config, expressionEvaluator ) ) + { + logParameter( parameter ); + } + } + + private void logDeprecatedMojo( MojoDescriptor mojoDescriptor ) + { + String message = MessageUtils.buffer() + .warning( "Goal '" ) + .warning( mojoDescriptor.getGoal() ) + .warning( "' is deprecated: " ) + .warning( mojoDescriptor.getDeprecated() ) + .toString(); + + LOGGER.warn( message ); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginConfigurationValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginConfigurationValidator.java new file mode 100644 index 000000000000..8252782d38a0 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginConfigurationValidator.java @@ -0,0 +1,39 @@ +package org.apache.maven.plugin.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.plugin.descriptor.MojoDescriptor; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; +import org.codehaus.plexus.configuration.PlexusConfiguration; + +/** + * Service responsible for validating plugin configuration. + * + * @author Slawomir Jaranowski + */ +interface MavenPluginConfigurationValidator +{ + /** + * Check mojo configuration. + */ + void validate( MojoDescriptor mojoDescriptor, + PlexusConfiguration pomConfiguration, + ExpressionEvaluator expressionEvaluator ); +} diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator.java new file mode 100644 index 000000000000..3165b426e80b --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator.java @@ -0,0 +1,85 @@ +package org.apache.maven.plugin.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.Named; +import javax.inject.Singleton; + +import org.apache.maven.plugin.descriptor.MojoDescriptor; +import org.apache.maven.plugin.descriptor.Parameter; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; +import org.codehaus.plexus.configuration.PlexusConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Print warnings if read-only parameters of a plugin are used in configuration. + * + * @author Slawomir Jaranowski + */ +@Named +@Singleton +public class ReadOnlyPluginParametersValidator extends AbstractMavenPluginParametersValidator +{ + private static final Logger LOGGER = LoggerFactory.getLogger( ReadOnlyPluginParametersValidator.class ); + + @Override + protected Logger getLogger() + { + return LOGGER; + } + + @Override + protected String getParameterLogReason( Parameter parameter ) + { + return "is read-only, must not be used in configuration"; + } + + @Override + public void validate( MojoDescriptor mojoDescriptor, PlexusConfiguration pomConfiguration, + ExpressionEvaluator expressionEvaluator ) + { + if ( !LOGGER.isWarnEnabled() ) + { + return; + } + + if ( mojoDescriptor.getParameters() == null ) + { + return; + } + + mojoDescriptor.getParameters().stream() + .filter( parameter -> !parameter.isEditable() ) + .forEach( parameter -> checkParameter( parameter, pomConfiguration, expressionEvaluator ) ); + } + + protected void checkParameter( Parameter parameter, + PlexusConfiguration pomConfiguration, + ExpressionEvaluator expressionEvaluator ) + { + PlexusConfiguration config = pomConfiguration.getChild( parameter.getName(), false ); + + if ( isValueSet( config, expressionEvaluator ) ) + { + logParameter( parameter ); + } + } +} diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/ValidatingConfigurationListener.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/ValidatingConfigurationListener.java index 99b18af7c7a9..c04f44821e96 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/internal/ValidatingConfigurationListener.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/ValidatingConfigurationListener.java @@ -36,7 +36,6 @@ class ValidatingConfigurationListener implements ConfigurationListener { - private final Object mojo; private final ConfigurationListener delegate; @@ -93,5 +92,4 @@ private void notify( String fieldName, Object value ) missingParameters.remove( fieldName ); } } - } diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java index 82e32fb310b3..2d2d1cba7b41 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java @@ -25,7 +25,10 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.apache.maven.artifact.repository.metadata.Metadata; import org.apache.maven.artifact.repository.metadata.Versioning; @@ -49,6 +52,7 @@ import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.SessionData; import org.eclipse.aether.metadata.DefaultMetadata; import org.eclipse.aether.repository.ArtifactRepository; import org.eclipse.aether.repository.RemoteRepository; @@ -72,6 +76,8 @@ public class DefaultPluginVersionResolver private static final String REPOSITORY_CONTEXT = "plugin"; + private static final Object CACHE_KEY = new Object(); + @Requirement private Logger logger; @@ -91,12 +97,26 @@ public PluginVersionResult resolve( PluginVersionRequest request ) if ( result == null ) { - result = resolveFromRepository( request ); + ConcurrentMap cache = getCache( request.getRepositorySession().getData() ); + Key key = getKey( request ); + result = cache.get( key ); - if ( logger.isDebugEnabled() ) + if ( result == null ) { - logger.debug( "Resolved plugin version for " + request.getGroupId() + ":" + request.getArtifactId() - + " to " + result.getVersion() + " from repository " + result.getRepository() ); + result = resolveFromRepository( request ); + + if ( logger.isDebugEnabled() ) + { + logger.debug( "Resolved plugin version for " + request.getGroupId() + ":" + request.getArtifactId() + + " to " + result.getVersion() + " from repository " + result.getRepository() ); + } + + cache.putIfAbsent( key, result ); + } + else if ( logger.isDebugEnabled() ) + { + logger.debug( "Reusing cached resolved plugin version for " + request.getGroupId() + ":" + + request.getArtifactId() + " to " + result.getVersion() + " from POM " + request.getPom() ); } } else if ( logger.isDebugEnabled() ) @@ -384,6 +404,67 @@ private PluginVersionResult resolveFromProject( PluginVersionRequest request, Li return null; } + @SuppressWarnings( "unchecked" ) + private ConcurrentMap getCache( SessionData data ) + { + ConcurrentMap cache = + ( ConcurrentMap ) data.get( CACHE_KEY ); + while ( cache == null ) + { + cache = new ConcurrentHashMap<>( 256 ); + if ( data.set( CACHE_KEY, null, cache ) ) + { + break; + } + cache = ( ConcurrentMap ) data.get( CACHE_KEY ); + } + return cache; + } + + private static Key getKey( PluginVersionRequest request ) + { + return new Key( request.getGroupId(), request.getArtifactId(), request.getRepositories() ); + } + + static class Key + { + final String groupId; + final String artifactId; + final List repositories; + final int hash; + + Key( String groupId, String artifactId, List repositories ) + { + this.groupId = groupId; + this.artifactId = artifactId; + this.repositories = repositories; + this.hash = Objects.hash( groupId, artifactId, repositories ); + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + Key key = ( Key ) o; + return groupId.equals( key.groupId ) + && artifactId.equals( key.artifactId ) + && repositories.equals( key.repositories ); + } + + @Override + public int hashCode() + { + return hash; + } + } + static class Versions { diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 7e18f1ef3ce2..616dad121892 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -56,12 +56,14 @@ import org.apache.maven.model.building.ModelBuildingException; import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelBuildingResult; +import org.apache.maven.model.building.ModelCache; import org.apache.maven.model.building.ModelProblem; import org.apache.maven.model.building.ModelProcessor; import org.apache.maven.model.building.ModelSource; import org.apache.maven.model.building.StringModelSource; import org.apache.maven.model.resolution.ModelResolver; import org.apache.maven.repository.internal.ArtifactDescriptorUtils; +import org.apache.maven.repository.internal.ModelCacheFactory; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.logging.Logger; @@ -111,7 +113,8 @@ public class DefaultProjectBuilder @Requirement private ProjectDependenciesResolver dependencyResolver; - private final ReactorModelCache modelCache = new ReactorModelCache(); + @Requirement + private ModelCacheFactory modelCacheFactory; // ---------------------------------------------------------------------- // MavenProjectBuilder Implementation @@ -122,7 +125,8 @@ public ProjectBuildingResult build( File pomFile, ProjectBuildingRequest request throws ProjectBuildingException { return build( pomFile, new FileModelSource( pomFile ), - new InternalConfig( request, null, useGlobalModelCache() ? getModelCache() : null ) ); + new InternalConfig( request, null, + useGlobalModelCache() ? createModelCache( request.getRepositorySession() ) : null ) ); } private boolean useGlobalModelCache() @@ -135,7 +139,8 @@ public ProjectBuildingResult build( ModelSource modelSource, ProjectBuildingRequ throws ProjectBuildingException { return build( null, modelSource, - new InternalConfig( request, null, useGlobalModelCache() ? getModelCache() : null ) ); + new InternalConfig( request, null, + useGlobalModelCache() ? createModelCache( request.getRepositorySession() ) : null ) ); } private ProjectBuildingResult build( File pomFile, ModelSource modelSource, InternalConfig config ) @@ -306,7 +311,8 @@ public ProjectBuildingResult build( Artifact artifact, boolean allowStubModel, P org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact( artifact ); pomArtifact = ArtifactDescriptorUtils.toPomArtifact( pomArtifact ); - InternalConfig config = new InternalConfig( request, null, useGlobalModelCache() ? getModelCache() : null ); + InternalConfig config = new InternalConfig( request, null, + useGlobalModelCache() ? createModelCache( request.getRepositorySession() ) : null ); boolean localProject; @@ -369,7 +375,7 @@ public List build( List pomFiles, boolean recursive ReactorModelPool modelPool = new ReactorModelPool(); InternalConfig config = new InternalConfig( request, modelPool, - useGlobalModelCache() ? getModelCache() : new ReactorModelCache() ); + useGlobalModelCache() ? createModelCache( request.getRepositorySession() ) : new ReactorModelCache() ); Map projectIndex = new HashMap<>( 256 ); @@ -1058,9 +1064,9 @@ class InternalConfig private final ReactorModelPool modelPool; - private final ReactorModelCache modelCache; + private final ModelCache modelCache; - InternalConfig( ProjectBuildingRequest request, ReactorModelPool modelPool, ReactorModelCache modelCache ) + InternalConfig( ProjectBuildingRequest request, ReactorModelPool modelPool, ModelCache modelCache ) { this.request = request; this.modelPool = modelPool; @@ -1073,9 +1079,9 @@ class InternalConfig } - private ReactorModelCache getModelCache() + private ModelCache createModelCache( RepositorySystemSession session ) { - return this.modelCache; + return modelCacheFactory.createCache( session ); } } 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 0409fb885bde..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 @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import org.apache.maven.RepositoryUtils; import org.apache.maven.artifact.Artifact; @@ -186,8 +187,12 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request ) { 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 " - + child.getDependency().getArtifact() ); + + relocated + ( message != null ? ": " + message : "" ) ); } } } @@ -269,7 +274,7 @@ public boolean visitEnter( DependencyNode node ) { final String premanagedScope = DependencyManagerUtils.getPremanagedScope( node ); buffer.append( " (scope managed from " ); - buffer.append( StringUtils.defaultString( premanagedScope, "default" ) ); + buffer.append( Objects.toString( premanagedScope, "default" ) ); buffer.append( ')' ); } @@ -277,7 +282,7 @@ public boolean visitEnter( DependencyNode node ) { final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node ); buffer.append( " (version managed from " ); - buffer.append( StringUtils.defaultString( premanagedVersion, "default" ) ); + buffer.append( Objects.toString( premanagedVersion, "default" ) ); buffer.append( ')' ); } @@ -285,7 +290,7 @@ public boolean visitEnter( DependencyNode node ) { final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional( node ); buffer.append( " (optionality managed from " ); - buffer.append( StringUtils.defaultString( premanagedOptional, "default" ) ); + buffer.append( Objects.toString( premanagedOptional, "default" ) ); buffer.append( ')' ); } @@ -296,7 +301,7 @@ public boolean visitEnter( DependencyNode node ) DependencyManagerUtils.getPremanagedExclusions( node ); buffer.append( " (exclusions managed from " ); - buffer.append( StringUtils.defaultString( premanagedExclusions, "default" ) ); + buffer.append( Objects.toString( premanagedExclusions, "default" ) ); buffer.append( ')' ); } @@ -307,7 +312,7 @@ public boolean visitEnter( DependencyNode node ) DependencyManagerUtils.getPremanagedProperties( node ); buffer.append( " (properties managed from " ); - buffer.append( StringUtils.defaultString( premanagedProperties, "default" ) ); + buffer.append( Objects.toString( premanagedProperties, "default" ) ); buffer.append( ')' ); } } diff --git a/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionException.java b/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionException.java index 50e601e7e97e..ecd015182361 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionException.java +++ b/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionException.java @@ -26,7 +26,7 @@ public class DependencyResolutionException extends Exception { - private DependencyResolutionResult result; + private final transient DependencyResolutionResult result; public DependencyResolutionException( DependencyResolutionResult result, String message, Throwable cause ) { diff --git a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java index ceb39e21a231..db0f4a90116f 100644 --- a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java +++ b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java @@ -72,6 +72,8 @@ import org.codehaus.plexus.util.xml.Xpp3Dom; import org.eclipse.aether.graph.DependencyFilter; import org.eclipse.aether.repository.RemoteRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The concern of the project is provide runtime values based on the model. @@ -90,6 +92,9 @@ public class MavenProject implements Cloneable { + + private static final Logger LOGGER = LoggerFactory.getLogger( MavenProject.class ); + public static final String EMPTY_PROJECT_GROUP_ID = "unknown"; public static final String EMPTY_PROJECT_ARTIFACT_ID = "empty-project"; @@ -122,7 +127,7 @@ public class MavenProject private List remotePluginRepositories; - private List attachedArtifacts; + private List attachedArtifacts = new ArrayList<>(); private MavenProject executionProject; @@ -921,12 +926,23 @@ public Map> getInjectedProfileIds() * coordinates. * * @param artifact the artifact to add or replace. - * @throws DuplicateArtifactAttachmentException + * @deprecated Please use {@link MavenProjectHelper} + * @throws DuplicateArtifactAttachmentException will never happen but leave it for backward compatibility */ public void addAttachedArtifact( Artifact artifact ) throws DuplicateArtifactAttachmentException { - getAttachedArtifacts().add( artifact ); + // if already there we remove it and add again + int index = attachedArtifacts.indexOf( artifact ); + if ( index >= 0 ) + { + LOGGER.warn( "artifact {} already attached, replace previous instance", artifact ); + attachedArtifacts.set( index, artifact ); + } + else + { + attachedArtifacts.add( artifact ); + } } public List getAttachedArtifacts() @@ -935,7 +951,7 @@ public List getAttachedArtifacts() { attachedArtifacts = new ArrayList<>(); } - return attachedArtifacts; + return Collections.unmodifiableList( attachedArtifacts ); } public Xpp3Dom getGoalConfiguration( String pluginGroupId, String pluginArtifactId, String executionId, 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 1c40af8b9869..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 @@ -180,6 +180,7 @@ public ResolutionGroup retrieve( MetadataResolutionRequest request ) Artifact relocatedArtifact = null; + // TODO hack: don't rebuild model if it was already loaded during reactor resolution final WorkspaceReader workspace = legacySupport.getRepositorySession().getWorkspaceReader(); Model model = null; if ( workspace instanceof MavenWorkspaceReader ) @@ -586,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/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java b/maven-core/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java index d3ffd925ec61..5b63317bf532 100644 --- a/maven-core/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java @@ -147,12 +147,8 @@ private File getFile( String pathPattern, String basedirSysProp, String altLocat // --------------------------------------------------------------------------------- // path = path.replaceAll( "//", "/" ); - return new File( path ).getAbsoluteFile(); - } - else - { - return new File( path ).getAbsoluteFile(); } + return new File( path ).getAbsoluteFile(); } } diff --git a/maven-core/src/main/resources/META-INF/maven/extension.xml b/maven-core/src/main/resources/META-INF/maven/extension.xml index 6bd836927364..a419b3e835df 100644 --- a/maven-core/src/main/resources/META-INF/maven/extension.xml +++ b/maven-core/src/main/resources/META-INF/maven/extension.xml @@ -30,6 +30,7 @@ under the License. org.apache.maven.exception org.apache.maven.execution org.apache.maven.execution.scope + org.apache.maven.graph org.apache.maven.lifecycle org.apache.maven.model org.apache.maven.monitor @@ -69,6 +70,7 @@ under the License. org.eclipse.aether.spi org.eclipse.aether.transfer org.eclipse.aether.version + org.eclipse.aether.util org.codehaus.plexus.classworlds @@ -94,9 +96,11 @@ under the License. javax.inject.* - + javax.annotation.* @@ -164,9 +168,11 @@ under the License. org.apache.maven.resolver:maven-resolver-api org.apache.maven.resolver:maven-resolver-spi org.apache.maven.resolver:maven-resolver-impl + org.apache.maven.resolver:maven-resolver-util + org.apache.maven.resolver:maven-resolver-connector-basic javax.inject:javax.inject - javax.annotation:jsr250-api + javax.annotation:javax.annotation-api org.slf4j:slf4j-api org.fusesource.jansi:jansi @@ -179,6 +185,8 @@ under the License. org.eclipse.aether:aether-api org.eclipse.aether:aether-spi org.eclipse.aether:aether-impl + org.eclipse.aether:aether-util + org.eclipse.aether:aether-connector-basic - org.apache.maven.plugins:maven-install-plugin:2.4:install + org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install - org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy + org.apache.maven.plugins:maven-deploy-plugin:3.0.0-M2:deploy @@ -85,10 +85,10 @@ Mappings to default lifecycle, specific for each packaging. org.apache.maven.plugins:maven-jar-plugin:2.4:jar - org.apache.maven.plugins:maven-install-plugin:2.4:install + org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install - org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy + org.apache.maven.plugins:maven-deploy-plugin:3.0.0-M2:deploy @@ -129,10 +129,10 @@ Mappings to default lifecycle, specific for each packaging. org.apache.maven.plugins:maven-ejb-plugin:2.3:ejb - org.apache.maven.plugins:maven-install-plugin:2.4:install + org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install - org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy + org.apache.maven.plugins:maven-deploy-plugin:3.0.0-M2:deploy @@ -177,10 +177,10 @@ Mappings to default lifecycle, specific for each packaging. org.apache.maven.plugins:maven-plugin-plugin:3.2:addPluginArtifactMetadata - org.apache.maven.plugins:maven-install-plugin:2.4:install + org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install - org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy + org.apache.maven.plugins:maven-deploy-plugin:3.0.0-M2:deploy @@ -221,10 +221,10 @@ Mappings to default lifecycle, specific for each packaging. org.apache.maven.plugins:maven-war-plugin:2.2:war - org.apache.maven.plugins:maven-install-plugin:2.4:install + org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install - org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy + org.apache.maven.plugins:maven-deploy-plugin:3.0.0-M2:deploy @@ -256,10 +256,10 @@ Mappings to default lifecycle, specific for each packaging. org.apache.maven.plugins:maven-ear-plugin:2.8:ear - org.apache.maven.plugins:maven-install-plugin:2.4:install + org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install - org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy + org.apache.maven.plugins:maven-deploy-plugin:3.0.0-M2:deploy @@ -300,10 +300,10 @@ Mappings to default lifecycle, specific for each packaging. org.apache.maven.plugins:maven-rar-plugin:2.2:rar - org.apache.maven.plugins:maven-install-plugin:2.4:install + org.apache.maven.plugins:maven-install-plugin:3.0.0-M1:install - org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy + org.apache.maven.plugins:maven-deploy-plugin:3.0.0-M2:deploy 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..db7a17f8ec63 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,10 @@ protected MavenSession createMavenSession( File pom, Properties executionPropert .setLocalRepository( request.getLocalRepository() ) .setRemoteRepositories( request.getRemoteRepositories() ) .setPluginArtifactRepositories( request.getPluginArtifactRepositories() ) - .setSystemProperties( executionProperties ); + .setSystemProperties( executionProperties ) + .setUserProperties( new Properties() ); + + initRepoSession( configuration ); List projects = new ArrayList<>(); @@ -173,8 +176,6 @@ protected MavenSession createMavenSession( File pom, Properties executionPropert projects.add( project ); } - initRepoSession( configuration ); - MavenSession session = new MavenSession( getContainer(), configuration.getRepositorySession(), request, new DefaultMavenExecutionResult() ); diff --git a/maven-core/src/test/java/org/apache/maven/DefaultMavenTest.java b/maven-core/src/test/java/org/apache/maven/DefaultMavenTest.java index ab073a6324b6..a0a0b92b4495 100644 --- a/maven-core/src/test/java/org/apache/maven/DefaultMavenTest.java +++ b/maven-core/src/test/java/org/apache/maven/DefaultMavenTest.java @@ -1,7 +1,18 @@ package org.apache.maven; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DefaultArtifact; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenExecutionResult; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectHelper; +import org.apache.maven.repository.internal.MavenWorkspaceReader; +import org.codehaus.plexus.component.annotations.Component; + +import java.io.File; +import java.nio.file.Files; +import java.util.concurrent.atomic.AtomicReference; import static java.util.Arrays.asList; @@ -23,7 +34,34 @@ * specific language governing permissions and limitations * under the License. */ -public class DefaultMavenTest extends AbstractCoreMavenComponentTestCase{ +public class DefaultMavenTest + extends AbstractCoreMavenComponentTestCase +{ + @Component( role = AbstractMavenLifecycleParticipant.class, hint = "WsrClassCatcher" ) + private static final class WsrClassCatcher extends AbstractMavenLifecycleParticipant + { + private final AtomicReference> wsrClassRef = new AtomicReference<>( null ); + + @Override + public void afterProjectsRead( MavenSession session ) throws MavenExecutionException + { + wsrClassRef.set( session.getRepositorySession().getWorkspaceReader().getClass() ); + } + } + + public void testEnsureResolverSessionHasMavenWorkspaceReader() throws Exception + { + WsrClassCatcher wsrClassCatcher = ( WsrClassCatcher ) getContainer() + .lookup( AbstractMavenLifecycleParticipant.class, "WsrClassCatcher" ); + Maven maven = getContainer().lookup( Maven.class ); + MavenExecutionRequest request = createMavenExecutionRequest( getProject( "simple" ) ).setGoals( asList("validate") ); + + MavenExecutionResult result = maven.execute( request ); + + Class wsrClass = wsrClassCatcher.wsrClassRef.get(); + assertTrue( "is null", wsrClass != null ); + assertTrue( String.valueOf( wsrClass ), MavenWorkspaceReader.class.isAssignableFrom( wsrClass ) ); + } public void testThatErrorDuringProjectDependencyGraphCreationAreStored() throws Exception @@ -42,4 +80,24 @@ protected String getProjectsDirectory() return "src/test/projects/default-maven"; } + + public void testMavenProjectNoDuplicateArtifacts() + throws Exception + { + MavenProjectHelper mavenProjectHelper = lookup( MavenProjectHelper.class ); + MavenProject mavenProject = new MavenProject(); + mavenProject.setArtifact( new DefaultArtifact( "g", "a", "1.0", Artifact.SCOPE_TEST, "jar", "", null ) ); + File artifactFile = Files.createTempFile( "foo", "tmp").toFile(); + try + { + mavenProjectHelper.attachArtifact( mavenProject, "sources", artifactFile ); + assertEquals( 1, mavenProject.getAttachedArtifacts().size() ); + mavenProjectHelper.attachArtifact( mavenProject, "sources", artifactFile ); + assertEquals( 1, mavenProject.getAttachedArtifacts().size() ); + } finally + { + Files.deleteIfExists( artifactFile.toPath() ); + } + } + } diff --git a/maven-core/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerTest.java b/maven-core/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerTest.java index 69f59fdb364e..2803d8d80a29 100644 --- a/maven-core/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerTest.java +++ b/maven-core/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerTest.java @@ -33,7 +33,6 @@ public void testAptConsistency() { File apt = getTestFile( "src/site/apt/artifact-handlers.apt" ); - @SuppressWarnings( "unchecked" ) List lines = FileUtils.loadFile( apt ); for ( String line : lines ) diff --git a/maven-core/src/test/java/org/apache/maven/internal/MultilineMessageHelperTest.java b/maven-core/src/test/java/org/apache/maven/internal/MultilineMessageHelperTest.java new file mode 100644 index 000000000000..42fe36fd58ab --- /dev/null +++ b/maven-core/src/test/java/org/apache/maven/internal/MultilineMessageHelperTest.java @@ -0,0 +1,71 @@ +package org.apache.maven.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 java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class MultilineMessageHelperTest +{ + + @Test + public void testBuilderCommon() + { + List msgs = new ArrayList<>(); + msgs.add( "*****************************************************************" ); + msgs.add( "* Your build is requesting parallel execution, but project *" ); + msgs.add( "* contains the following plugin(s) that have goals not marked *" ); + msgs.add( "* as @threadSafe to support parallel building. *" ); + msgs.add( "* While this /may/ work fine, please look for plugin updates *" ); + msgs.add( "* and/or request plugins be made thread-safe. *" ); + msgs.add( "* If reporting an issue, report it against the plugin in *" ); + msgs.add( "* question, not against maven-core *" ); + msgs.add( "*****************************************************************" ); + + assertEquals( msgs, MultilineMessageHelper.format( + "Your build is requesting parallel execution, but project contains the following " + + "plugin(s) that have goals not marked as @threadSafe to support parallel building.", + "While this /may/ work fine, please look for plugin updates and/or " + + "request plugins be made thread-safe.", + "If reporting an issue, report it against the plugin in question, not against maven-core" + ) ); + } + + @Test + public void testMojoExecutor() + { + List msgs = new ArrayList<>(); + msgs.add( "*****************************************************************" ); + msgs.add( "* An aggregator Mojo is already executing in parallel build, *" ); + msgs.add( "* but aggregator Mojos require exclusive access to reactor to *" ); + msgs.add( "* prevent race conditions. This mojo execution will be blocked *" ); + msgs.add( "* until the aggregator work is done. *" ); + msgs.add( "*****************************************************************" ); + + assertEquals( msgs, MultilineMessageHelper.format( + "An aggregator Mojo is already executing in parallel build, but aggregator " + + "Mojos require exclusive access to reactor to prevent race conditions. This " + + "mojo execution will be blocked until the aggregator work is done." ) ); + } +} diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java index 690532c77d85..d7a84d15a48c 100644 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java +++ b/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java @@ -50,9 +50,11 @@ public void testLifecycle() { final List cycles = defaultLifeCycles.getLifeCycles(); assertNotNull( cycles ); - final Lifecycle lifecycle = cycles.get( 0 ); - assertEquals( "default", lifecycle.getId() ); - assertEquals( 23, lifecycle.getPhases().size() ); + final Lifecycle lifecycle0 = cycles.get( 0 ); + assertEquals( "clean", lifecycle0.getId() ); + final Lifecycle lifecycle1 = cycles.get( 1 ); + assertEquals( "default", lifecycle1.getId() ); + assertEquals( 23, lifecycle1.getPhases().size() ); } 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/DefaultLifecyclesStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/DefaultLifecyclesStub.java index 1dc2b6b0a633..a1a95322941b 100644 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/DefaultLifecyclesStub.java +++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/DefaultLifecyclesStub.java @@ -47,7 +47,6 @@ public static DefaultLifecycles createDefaultLifecycles() List stubSiteCycle = Arrays.asList( PRE_SITE.getPhase(), SITE.getPhase(), POST_SITE.getPhase(), SITE_DEPLOY.getPhase() ); - @SuppressWarnings( "unchecked" ) Iterator> lcs = Arrays.asList( stubDefaultCycle, stubCleanCycle, stubSiteCycle ).iterator(); Map lifeCycles = new HashMap<>(); 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..350dccd44b72 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 @@ -17,13 +17,13 @@ import org.apache.maven.execution.MavenSession; import org.apache.maven.lifecycle.LifecycleExecutionException; -import org.apache.maven.lifecycle.internal.DependencyContext; 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; +import org.apache.maven.project.MavenProject; import java.util.ArrayList; import java.util.Collections; @@ -39,27 +39,27 @@ public class MojoExecutorStub public List executions = Collections.synchronizedList( new ArrayList() ); @Override - public void execute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex, - DependencyContext dependencyContext, PhaseRecorder phaseRecorder ) + public void execute( MavenSession session, List mojoExecutions, ProjectIndex projectIndex ) throws LifecycleExecutionException { - executions.add( mojoExecution ); + executions.addAll( mojoExecutions ); } @Override - public void execute( MavenSession session, List mojoExecutions, ProjectIndex projectIndex ) - throws LifecycleExecutionException + public List executeForkedExecutions( MojoExecution mojoExecution, MavenSession session, ProjectIndex projectIndex ) throws LifecycleExecutionException { - executions.addAll(mojoExecutions); + return null; } - 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; } diff --git a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java index e3809497d0f5..04a7ee5bc9cf 100644 --- a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java +++ b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java @@ -53,7 +53,7 @@ public class PluginParameterExpressionEvaluatorTest extends AbstractCoreMavenComponentTestCase { - private static final String FS = System.getProperty( "file.separator" ); + private static final String FS = File.separator; private RepositorySystem factory; 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/java/org/apache/maven/project/ExtensionDescriptorBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ExtensionDescriptorBuilderTest.java index 7a5e55d1eb1b..5ac8f611cf92 100644 --- a/maven-core/src/test/java/org/apache/maven/project/ExtensionDescriptorBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/ExtensionDescriptorBuilderTest.java @@ -25,7 +25,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import junit.framework.TestCase; @@ -61,14 +61,7 @@ protected void tearDown() private InputStream toStream( String xml ) { - try - { - return new ByteArrayInputStream( xml.getBytes( "UTF-8" ) ); - } - catch ( UnsupportedEncodingException e ) - { - throw new IllegalStateException( e ); - } + return new ByteArrayInputStream( xml.getBytes( StandardCharsets.UTF_8 ) ); } public void testEmptyDescriptor() 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 9e16ebc59487..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" ) ); } @@ -975,7 +975,7 @@ public void testDependencyInheritance() { PomTestWrapper pom = buildPom( "dependency-inheritance/sub" ); assertEquals( 1, ( (List) pom.getValue( "dependencies" ) ).size() ); - assertEquals( "4.4", pom.getValue( "dependencies[1]/version" ) ); + assertEquals( "4.13", pom.getValue( "dependencies[1]/version" ) ); } /** MNG-4034 */ @@ -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-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java index 4833b0035119..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 @@ -26,20 +26,23 @@ import static org.junit.Assert.assertThat; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; 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; import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.Plugin; import org.apache.maven.model.building.FileModelSource; import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelSource; import org.apache.maven.shared.utils.io.FileUtils; -import com.google.common.io.Files; public class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase @@ -117,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 artifactsResultInAnotherThread = new AtomicInteger(); + Thread t = new Thread(new Runnable() { + @Override + public void run() { + artifactsResultInAnotherThread.set(project.getArtifacts().size()); + } + }); + t.start(); + t.join(); + assertEquals( project.getArtifacts().size(), artifactsResultInAnotherThread.get() ); } public void testDontResolveDependencies() @@ -142,22 +157,23 @@ public void testReadModifiedPoms() throws Exception { String initialValue = System.setProperty( DefaultProjectBuilder.DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY, Boolean.toString( true ) ); // TODO a similar test should be created to test the dependency management (basically all usages // of DefaultModelBuilder.getCache() are affected by MNG-6530 - File tempDir = Files.createTempDir(); - FileUtils.copyDirectoryStructure (new File( "src/test/resources/projects/grandchild-check"), tempDir ); + + Path tempDir = Files.createTempDirectory( null ); + FileUtils.copyDirectoryStructure ( new File( "src/test/resources/projects/grandchild-check" ), tempDir.toFile() ); try { MavenSession mavenSession = createMavenSession( null ); ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest(); configuration.setRepositorySession( mavenSession.getRepositorySession() ); org.apache.maven.project.ProjectBuilder projectBuilder = lookup( org.apache.maven.project.ProjectBuilder.class ); - File child = new File( tempDir, "child/pom.xml" ); + File child = new File( tempDir.toFile(), "child/pom.xml" ); // build project once projectBuilder.build( child, configuration ); // modify parent - File parent = new File( tempDir, "pom.xml" ); + File parent = new File( tempDir.toFile(), "pom.xml" ); String parentContent = FileUtils.fileRead( parent ); parentContent = parentContent.replaceAll( "pom", - "pomaddedValue" ); + "pomaddedValue" ); FileUtils.fileWrite( parent, "UTF-8", parentContent ); // re-build pom with modified parent ProjectBuildingResult result = projectBuilder.build( child, configuration ); @@ -173,7 +189,7 @@ public void testReadModifiedPoms() throws Exception { { System.setProperty( DefaultProjectBuilder.DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY, initialValue ); } - FileUtils.deleteDirectory( tempDir ); + FileUtils.deleteDirectory( tempDir.toFile() ); } } @@ -303,7 +319,7 @@ private MavenProject findChildProject( List results ) return null; } - private void assertResultShowNoError(List results) + private void assertResultShowNoError( List results ) { for ( ProjectBuildingResult result : results ) { @@ -320,12 +336,25 @@ public void testBuildProperties() ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest(); configuration.setRepositorySession( mavenSession.getRepositorySession() ); configuration.setResolveDependencies( true ); - List result = projectBuilder.build( Collections.singletonList(file), true, configuration ); - MavenProject project = result.get(0).getProject(); + List result = projectBuilder.build( Collections.singletonList( file ), true, configuration ); + MavenProject project = result.get( 0 ).getProject(); // verify a few typical parameters are not duplicated assertEquals( 1, project.getTestCompileSourceRoots().size() ); assertEquals( 1, project.getCompileSourceRoots().size() ); assertEquals( 1, project.getMailingLists().size() ); assertEquals( 1, project.getResources().size() ); } + + public void testPropertyInPluginManagementGroupId() + throws Exception + { + File pom = getProject( "MNG-6983" ); + + MavenSession session = createMavenSession( pom ); + MavenProject project = session.getCurrentProject(); + + for (Plugin buildPlugin : project.getBuildPlugins()) { + assertNotNull( "Missing version for build plugin " + buildPlugin.getKey(), buildPlugin.getVersion() ); + } + } } diff --git a/maven-core/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java b/maven-core/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java index 2c20d3c21fb0..f04d24876b5a 100644 --- a/maven-core/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java @@ -47,7 +47,7 @@ public class DefaultToolchainsBuilderTest { - private static final String LS = System.getProperty( "line.separator" ); + private static final String LS = System.lineSeparator(); @Spy private DefaultToolchainsReader toolchainsReader; diff --git a/maven-core/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java b/maven-core/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java index bf745c2a2ec7..0efda4d36596 100644 --- a/maven-core/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java +++ b/maven-core/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java @@ -30,7 +30,7 @@ public class ToolchainsBuildingExceptionTest { - private static final String LS = System.getProperty( "line.separator" ); + private static final String LS = System.lineSeparator(); @Test public void testNoProblems() diff --git a/maven-core/src/test/projects/default-maven/simple/pom.xml b/maven-core/src/test/projects/default-maven/simple/pom.xml new file mode 100644 index 000000000000..0221f8208f28 --- /dev/null +++ b/maven-core/src/test/projects/default-maven/simple/pom.xml @@ -0,0 +1,10 @@ + + 4.0.0 + + simple + simple + 1.0-SNAPSHOT + pom + + diff --git a/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml b/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml index c19061ad9661..7d0850e48382 100644 --- a/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml +++ b/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml @@ -53,7 +53,7 @@ under the License. --> 1.0-alpha-9 1.2_Java1.3 - 3.8.1 + 4.13 1.0-beta-3.0.7 1.0-alpha-6 1.1 @@ -473,7 +473,7 @@ under the License. ${mercuryMp3Version}
    - org.sonatype.plexus + org.codehaus.plexus plexus-sec-dispatcher ${securityDispatcherVersion} diff --git a/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml b/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml index c19061ad9661..7d0850e48382 100644 --- a/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml +++ b/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml @@ -53,7 +53,7 @@ under the License. --> 1.0-alpha-9 1.2_Java1.3 - 3.8.1 + 4.13 1.0-beta-3.0.7 1.0-alpha-6 1.1 @@ -473,7 +473,7 @@ under the License. ${mercuryMp3Version} - org.sonatype.plexus + org.codehaus.plexus plexus-sec-dispatcher ${securityDispatcherVersion} diff --git a/maven-core/src/test/projects/project-builder/MNG-6983/parent-pom.xml b/maven-core/src/test/projects/project-builder/MNG-6983/parent-pom.xml new file mode 100644 index 000000000000..3aed9678e56a --- /dev/null +++ b/maven-core/src/test/projects/project-builder/MNG-6983/parent-pom.xml @@ -0,0 +1,38 @@ + + 4.0.0 + + org.example + parent + 0.0.1-SNAPSHOT + pom + + + org.codehaus.mojo + + + + + + + ${codehaus.groupId} + build-helper-maven-plugin + 3.2.0 + + + add-source-config + generate-sources + + add-source + + + + . + + + + + + + + + diff --git a/maven-core/src/test/projects/project-builder/MNG-6983/pom.xml b/maven-core/src/test/projects/project-builder/MNG-6983/pom.xml new file mode 100644 index 000000000000..648f7fc9e936 --- /dev/null +++ b/maven-core/src/test/projects/project-builder/MNG-6983/pom.xml @@ -0,0 +1,22 @@ + + 4.0.0 + + + org.example + parent + 0.0.1-SNAPSHOT + ./parent-pom.xml + + + child + jar + + + + + ${codehaus.groupId} + build-helper-maven-plugin + + + + diff --git a/maven-core/src/test/projects/project-builder/it0063/jdk/jre/placeholder.txt b/maven-core/src/test/projects/project-builder/it0063/jdk/jre/placeholder.txt index e26e86087ce3..4a9eb145a1e3 100644 --- a/maven-core/src/test/projects/project-builder/it0063/jdk/jre/placeholder.txt +++ b/maven-core/src/test/projects/project-builder/it0063/jdk/jre/placeholder.txt @@ -1 +1 @@ -need it so that empty folder does not get deleted \ No newline at end of file +need it so that empty directory does not get deleted diff --git a/maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt b/maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt index e26e86087ce3..4a9eb145a1e3 100644 --- a/maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt +++ b/maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt @@ -1 +1 @@ -need it so that empty folder does not get deleted \ No newline at end of file +need it so that empty directory does not get deleted diff --git a/maven-core/src/test/resources-project-builder/dependency-inheritance/pom.xml b/maven-core/src/test/resources-project-builder/dependency-inheritance/pom.xml index 736b793c8e87..8f9c028e3823 100644 --- a/maven-core/src/test/resources-project-builder/dependency-inheritance/pom.xml +++ b/maven-core/src/test/resources-project-builder/dependency-inheritance/pom.xml @@ -33,7 +33,7 @@ under the License. pom - 3.8.1 + 4.13 diff --git a/maven-core/src/test/resources-project-builder/dependency-inheritance/sub/pom.xml b/maven-core/src/test/resources-project-builder/dependency-inheritance/sub/pom.xml index aaf8e8e5ab58..832f49e321ff 100644 --- a/maven-core/src/test/resources-project-builder/dependency-inheritance/sub/pom.xml +++ b/maven-core/src/test/resources-project-builder/dependency-inheritance/sub/pom.xml @@ -25,7 +25,7 @@ junit junit - 4.4 + 4.13 test diff --git a/maven-core/src/test/resources-project-builder/micromailer/pom.xml b/maven-core/src/test/resources-project-builder/micromailer/pom.xml index a1329545bb0a..0e875a7a1d4c 100644 --- a/maven-core/src/test/resources-project-builder/micromailer/pom.xml +++ b/maven-core/src/test/resources-project-builder/micromailer/pom.xml @@ -48,7 +48,7 @@ org.codehaus.plexus plexus-utils - 1.5.5 + 3.3.0 jar compile @@ -97,7 +97,7 @@ junit junit - 3.8.2 + 4.13 jar test diff --git a/maven-core/src/test/resources/org/apache/maven/lifecycle/pom.xml b/maven-core/src/test/resources/org/apache/maven/lifecycle/pom.xml index cd0a3d81712e..5caaac1ba285 100644 --- a/maven-core/src/test/resources/org/apache/maven/lifecycle/pom.xml +++ b/maven-core/src/test/resources/org/apache/maven/lifecycle/pom.xml @@ -53,7 +53,7 @@ under the License. --> 1.0-alpha-9 1.2_Java1.3 - 3.8.1 + 4.13 1.0-beta-3.0.7-SNAPSHOT 1.0-alpha-6 1.1 @@ -473,7 +473,7 @@ under the License. ${mercuryMp3Version} - org.sonatype.plexus + org.codehaus.plexus plexus-sec-dispatcher ${securityDispatcherVersion} 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-embedder/pom.xml b/maven-embedder/pom.xml index 7af181714fa0..9142dfaaa6e1 100644 --- a/maven-embedder/pom.xml +++ b/maven-embedder/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.6.3 + 3.9.0-SNAPSHOT maven-embedder @@ -75,44 +75,37 @@ under the License. maven-shared-utils - com.google.inject - guice - no_aop - - - aopalliance - aopalliance - - - - com.google.code.findbugs - jsr305 - - - org.checkerframework - checker-compat-qual - - - com.google.errorprone - error_prone_annotations - - - com.google.j2objc - j2objc-annotations - - - org.codehaus.mojo - animal-sniffer-annotations - - - + com.google.inject + guice + no_aop + + + aopalliance + aopalliance + + + + com.google.guava + guava + + + + + com.google.guava + guava + + + com.google.guava + failureaccess + javax.inject javax.inject + javax.annotation - jsr250-api + javax.annotation-api org.codehaus.plexus @@ -127,11 +120,11 @@ under the License. org.eclipse.sisu.plexus - org.sonatype.plexus + org.codehaus.plexus plexus-sec-dispatcher - org.sonatype.plexus + org.codehaus.plexus plexus-cipher @@ -170,12 +163,6 @@ under the License. - - - src/main/resources - true - - @@ -201,7 +188,7 @@ under the License. org.codehaus.modello modello-maven-plugin - 1.0.0 + 1.1.0 src/main/mdo/core-extensions.mdo diff --git a/maven-embedder/src/examples/simple-project/pom.xml b/maven-embedder/src/examples/simple-project/pom.xml index 62de37aac1be..843b38e32b52 100644 --- a/maven-embedder/src/examples/simple-project/pom.xml +++ b/maven-embedder/src/examples/simple-project/pom.xml @@ -29,7 +29,7 @@ under the License. junit junit - 3.8.1 + 4.13 test diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java index 1e950106907f..2ad542457b31 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java @@ -103,9 +103,11 @@ public class CLIManager public static final String NO_TRANSFER_PROGRESS = "ntp"; + public static final String COLOR = "color"; + protected Options options; - @SuppressWarnings( { "static-access", "checkstyle:linelength" } ) + @SuppressWarnings( "checkstyle:linelength" ) public CLIManager() { options = new Options(); @@ -149,6 +151,8 @@ public CLIManager() options.addOption( Option.builder( "cpu" ).longOpt( "check-plugin-updates" ).desc( "Ineffective, only kept for backward compatibility" ).build() ); options.addOption( Option.builder( "up" ).longOpt( "update-plugins" ).desc( "Ineffective, only kept for backward compatibility" ).build() ); options.addOption( Option.builder( "npu" ).longOpt( "no-plugin-updates" ).desc( "Ineffective, only kept for backward compatibility" ).build() ); + + options.addOption( Option.builder().longOpt( COLOR ).hasArg().optionalArg( true ).desc( "Defines the color mode of the output. Supported are 'auto', 'always', 'never'." ).build() ); } public CommandLine parse( String[] args ) diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java index fb7823923309..57be1963295f 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java @@ -55,7 +55,7 @@ public final class CLIReportingUtils public static String showVersion() { - final String ls = System.getProperty( "line.separator" ); + final String ls = System.lineSeparator(); Properties properties = getBuildProperties(); StringBuilder version = new StringBuilder( 256 ); version.append( buffer().strong( createMavenVersionString( properties ) ) ).append( ls ); @@ -75,6 +75,13 @@ public static String showVersion() return version.toString(); } + public static String showVersionMinimal() + { + Properties properties = getBuildProperties(); + String version = reduce( properties.getProperty( BUILD_VERSION_PROPERTY ) ); + return ( version != null ? version : "" ); + } + /** * Create a human readable string containing the Maven version, buildnumber, and time of build * @@ -96,7 +103,7 @@ static String createMavenVersionString( Properties buildProperties ) msg += ( rev != null ? rev : "" ); if ( StringUtils.isNotBlank( timestamp ) ) { - String ts = formatTimestamp( Long.valueOf( timestamp ) ); + String ts = formatTimestamp( Long.parseLong( timestamp ) ); msg += ( rev != null ? "; " : "" ) + ts; } msg += ")"; 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 7d17e187d25d..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 @@ -113,6 +113,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.apache.maven.cli.CLIManager.COLOR; import static org.apache.maven.cli.ResolveFile.resolveFile; import static org.apache.maven.shared.utils.logging.MessageUtils.buffer; @@ -166,6 +167,8 @@ public class MavenCli private Map configurationProcessors; + private CLIManager cliManager; + public MavenCli() { this( null ); @@ -278,6 +281,7 @@ public int doMain( CliRequest cliRequest ) cli( cliRequest ); properties( cliRequest ); logging( cliRequest ); + informativeCommands( cliRequest ); version( cliRequest ); localContainer = container( cliRequest ); commands( cliRequest ); @@ -367,7 +371,7 @@ void cli( CliRequest cliRequest ) // slf4jLogger = new Slf4jStdoutLogger(); - CLIManager cliManager = new CLIManager(); + cliManager = new CLIManager(); List args = new ArrayList<>(); CommandLine mavenConfig = null; @@ -417,7 +421,10 @@ void cli( CliRequest cliRequest ) cliManager.displayHelp( System.out ); throw e; } + } + private void informativeCommands( CliRequest cliRequest ) throws ExitException + { if ( cliRequest.commandLine.hasOption( CLIManager.HELP ) ) { cliManager.displayHelp( System.out ); @@ -426,7 +433,14 @@ void cli( CliRequest cliRequest ) if ( cliRequest.commandLine.hasOption( CLIManager.VERSION ) ) { - System.out.println( CLIReportingUtils.showVersion() ); + if ( cliRequest.commandLine.hasOption( CLIManager.QUIET ) ) + { + System.out.println( CLIReportingUtils.showVersionMinimal() ); + } + else + { + System.out.println( CLIReportingUtils.showVersion() ); + } throw new ExitException( 0 ); } } @@ -498,18 +512,19 @@ else if ( cliRequest.quiet ) // LOG COLOR String styleColor = cliRequest.getUserProperties().getProperty( STYLE_COLOR_PROPERTY, "auto" ); - if ( "always".equals( styleColor ) ) + styleColor = cliRequest.commandLine.getOptionValue( COLOR, styleColor ); + if ( "always".equals( styleColor ) || "yes".equals( styleColor ) || "force".equals( styleColor ) ) { MessageUtils.setColorEnabled( true ); } - else if ( "never".equals( styleColor ) ) + else if ( "never".equals( styleColor ) || "no".equals( styleColor ) || "none".equals( styleColor ) ) { MessageUtils.setColorEnabled( false ); } - else if ( !"auto".equals( styleColor ) ) + else if ( !"auto".equals( styleColor ) && !"tty".equals( styleColor ) && !"if-tty".equals( styleColor ) ) { - throw new IllegalArgumentException( "Invalid color configuration option [" + styleColor - + "]. Supported values are (auto|always|never)." ); + throw new IllegalArgumentException( "Invalid color configuration value '" + styleColor + + "'. Supported are 'auto', 'always', 'never'." ); } else if ( cliRequest.commandLine.hasOption( CLIManager.BATCH_MODE ) || cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) ) @@ -690,6 +705,7 @@ protected void configure() private List loadCoreExtensions( CliRequest cliRequest, ClassRealm containerRealm, Set providedArtifacts ) + throws Exception { if ( cliRequest.multiModuleProjectDirectory == null ) { @@ -702,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 ) @@ -1592,7 +1595,7 @@ else if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) && commandLine.hasOption } else { - request.setDegreeOfConcurrency( Integer.valueOf( threadConfiguration ) ); + request.setDegreeOfConcurrency( Integer.parseInt( threadConfiguration ) ); } } @@ -1610,7 +1613,7 @@ else if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) && commandLine.hasOption int calculateDegreeOfConcurrencyWithCoreMultiplier( String threadConfiguration ) { int procs = Runtime.getRuntime().availableProcessors(); - return (int) ( Float.valueOf( threadConfiguration.replace( "C", "" ) ) * procs ); + return (int) ( Float.parseFloat( threadConfiguration.replace( "C", "" ) ) * procs ); } // ---------------------------------------------------------------------- diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/ResolveFile.java b/maven-embedder/src/main/java/org/apache/maven/cli/ResolveFile.java index 8622ce342962..7a1652e249c3 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/ResolveFile.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/ResolveFile.java @@ -20,6 +20,7 @@ */ import java.io.File; +import java.nio.file.Paths; /** * Resolve relative file path against the given base directory @@ -43,7 +44,7 @@ else if ( file.getPath().startsWith( File.separator ) ) } else { - return new File( baseDirectory, file.getPath() ).getAbsoluteFile(); + return Paths.get( baseDirectory, file.getPath() ).normalize().toFile(); } } } 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..89c9bed4db10 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 @@ -31,6 +31,7 @@ import org.apache.maven.RepositoryUtils; import org.apache.maven.cli.internal.extension.model.CoreExtension; import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.extension.internal.CoreExports; import org.apache.maven.extension.internal.CoreExtensionEntry; import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory; import org.apache.maven.model.Plugin; @@ -40,6 +41,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; @@ -55,12 +60,18 @@ @Named public class BootstrapCoreExtensionManager { + public static final String STRATEGY_PARENT_FIRST = "parent-first"; + public static final String STRATEGY_PLUGIN = "plugin"; + public static final String STRATEGY_SELF_FIRST = "self-first"; + private final Logger log; private final DefaultPluginDependenciesResolver pluginDependenciesResolver; private final DefaultRepositorySystemSessionFactory repositorySystemSessionFactory; + private final CoreExports coreExports; + private final ClassWorld classWorld; private final ClassRealm parentRealm; @@ -68,11 +79,13 @@ public class BootstrapCoreExtensionManager @Inject public BootstrapCoreExtensionManager( Logger log, DefaultPluginDependenciesResolver pluginDependenciesResolver, DefaultRepositorySystemSessionFactory repositorySystemSessionFactory, + CoreExports coreExports, PlexusContainer container ) { this.log = log; this.pluginDependenciesResolver = pluginDependenciesResolver; this.repositorySystemSessionFactory = repositorySystemSessionFactory; + this.coreExports = coreExports; this.classWorld = ( (DefaultPlexusContainer) container ).getClassWorld(); this.parentRealm = container.getContainerRealm(); } @@ -83,14 +96,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 +114,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 ) ); @@ -114,33 +130,86 @@ private CoreExtensionEntry createExtension( CoreExtension extension, List providedArtifacts = Collections.emptySet(); + String classLoadingStrategy = extension.getClassLoadingStrategy(); + if ( STRATEGY_PARENT_FIRST.equals( classLoadingStrategy ) ) + { + realm.importFrom( parentRealm, "" ); + } + else if ( STRATEGY_PLUGIN.equals( classLoadingStrategy ) ) + { + coreExports.getExportedPackages().forEach( ( p, cl ) -> realm.importFrom( cl, p ) ); + providedArtifacts = coreExports.getExportedArtifacts(); + } + else if ( STRATEGY_SELF_FIRST.equals( classLoadingStrategy ) ) + { + realm.setParentRealm( parentRealm ); + } + else + { + throw new IllegalArgumentException( "Unsupported class-loading strategy '" + + classLoadingStrategy + "'. Supported values are: " + STRATEGY_PARENT_FIRST + + ", " + STRATEGY_PLUGIN + " and " + STRATEGY_SELF_FIRST ); + } log.debug( "Populating class realm " + realm.getId() ); - realm.setParentRealm( parentRealm ); for ( Artifact artifact : artifacts ) { - File file = artifact.getFile(); - log.debug( " Included " + file ); - realm.addURL( file.toURI().toURL() ); + String id = artifact.getGroupId() + ":" + artifact.getArtifactId(); + if ( providedArtifacts.contains( id ) ) + { + log.debug( " Excluded " + id ); + } + else + { + File file = artifact.getFile(); + log.debug( " Included " + id + " located at " + file ); + realm.addURL( file.toURI().toURL() ); + } } return CoreExtensionEntry.discoverFrom( realm, Collections.singleton( artifacts.get( 0 ).getFile() ) ); } private List resolveExtension( CoreExtension extension, RepositorySystemSession repoSession, - List repositories, DependencyFilter dependencyFilter ) - throws PluginResolutionException + List repositories, DependencyFilter dependencyFilter, + Interpolator interpolator ) + throws ExtensionResolutionException + { + try + { + /* 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( interpolator.interpolate( extension.getGroupId() ) ); + plugin.setArtifactId( interpolator.interpolate( extension.getArtifactId() ) ); + plugin.setVersion( interpolator.interpolate( 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() ); + } + catch ( InterpolationException e ) + { + throw new ExtensionResolutionException( extension, e ); + } + } + + private static Interpolator createInterpolator( MavenExecutionRequest request ) { - 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; + StringSearchInterpolator interpolator = new StringSearchInterpolator(); + interpolator.addValueSource( new MapBasedValueSource( request.getUserProperties() ) ); + interpolator.addValueSource( new MapBasedValueSource( request.getSystemProperties() ) ); + return interpolator; } + } 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/java/org/apache/maven/cli/logging/impl/UnsupportedSlf4jBindingConfiguration.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/UnsupportedSlf4jBindingConfiguration.java index 4757cffabf42..222ab4d3f0ac 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/UnsupportedSlf4jBindingConfiguration.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/UnsupportedSlf4jBindingConfiguration.java @@ -54,7 +54,7 @@ public void activate() logger.warn( "The SLF4J binding actually used is not supported by Maven: {}", slf4jBinding ); logger.warn( "Maven supported bindings are:" ); - String ls = System.getProperty( "line.separator" ); + String ls = System.lineSeparator(); for ( Map.Entry> entry : supported.entrySet() ) { diff --git a/maven-embedder/src/main/mdo/core-extensions.mdo b/maven-embedder/src/main/mdo/core-extensions.mdo index e523d5abf325..968258d21dac 100644 --- a/maven-embedder/src/main/mdo/core-extensions.mdo +++ b/maven-embedder/src/main/mdo/core-extensions.mdo @@ -82,7 +82,41 @@ true String + + classLoadingStrategy + The class loading strategy: 'self-first' (the default), 'parent-first' (loads classes from the parent, then from the extension) or 'plugin' (follows the rules from extensions defined as plugins). + 1.1.0+ + self-first + false + 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(); + } + ]]> + + + diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/CLIManagerDocumentationTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/CLIManagerDocumentationTest.java index 3a78f335cf7f..7b136066e496 100644 --- a/maven-embedder/src/test/java/org/apache/maven/cli/CLIManagerDocumentationTest.java +++ b/maven-embedder/src/test/java/org/apache/maven/cli/CLIManagerDocumentationTest.java @@ -39,14 +39,16 @@ public class CLIManagerDocumentationTest extends TestCase { - private final static String LS = System.getProperty( "line.separator" ); + private final static String LS = System.lineSeparator(); private static class OptionComparator implements Comparator + + com.google.guava + guava + test + + + com.google.guava + failureaccess + test + org.xmlunit xmlunit-core 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 f981944f940f..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 @@ -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,10 +252,24 @@ 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 ) throws ModelBuildingException + { + return build( request, new LinkedHashSet() ); + } + + @SuppressWarnings( "checkstyle:methodlength" ) + protected ModelBuildingResult build( ModelBuildingRequest request, Collection importIds ) + throws ModelBuildingException { // phase 1 DefaultModelBuildingResult result = new DefaultModelBuildingResult(); @@ -310,7 +332,9 @@ public ModelBuildingResult build( ModelBuildingRequest request ) profileActivationContext, problems ); currentData.setActiveProfiles( activePomProfiles ); - Map interpolatedActivations = getProfileActivations( rawModel, false ); + Map interpolatedActivations = getInterpolatedActivations( rawModel, + profileActivationContext, + problems ); injectProfileActivations( tmpModel, interpolatedActivations ); // profile injection @@ -427,12 +451,58 @@ else if ( !parentIds.add( parentData.getId() ) ) if ( !request.isTwoPhaseBuilding() ) { - build( request, result ); + build( request, result, importIds ); } 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 @@ -811,7 +881,7 @@ private Model interpolateModel( Model model, ModelBuildingRequest request, Model problems.add( mpcr ); } - + } interpolatedModel.setPomFile( model.getPomFile() ); @@ -987,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 ) @@ -996,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 ) @@ -1029,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 ) ) @@ -1117,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 ) @@ -1126,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 ) @@ -1296,7 +1378,7 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque final ModelBuildingResult importResult; try { - importResult = build( importRequest ); + importResult = build( importRequest, importIds ); } catch ( ModelBuildingException e ) { diff --git a/maven-model-builder/src/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..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; @@ -43,6 +45,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 +112,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() @@ -126,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() @@ -225,6 +240,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/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/interpolation/ProblemDetectingValueSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ProblemDetectingValueSource.java index 4ed98d035dd3..0b29f20e71cc 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ProblemDetectingValueSource.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ProblemDetectingValueSource.java @@ -72,7 +72,6 @@ public Object getValue( String expression ) } @Override - @SuppressWarnings( "unchecked" ) public List getFeedback() { return valueSource.getFeedback(); diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java index 9b67a34e4a19..6853030daa63 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java @@ -369,7 +369,7 @@ void doInterpolate( Object target, InterpolateObjectAction ctx ) String interpolated = ctx.interpolate( value ); - if ( !interpolated.equals( value ) ) + if ( interpolated != null && !interpolated.equals( value ) ) { field.set( target, interpolated ); } @@ -463,7 +463,7 @@ void doInterpolate( Object target, InterpolateObjectAction ctx ) { String interpolated = ctx.interpolate( (String) value ); - if ( !interpolated.equals( value ) ) + if ( interpolated != null && !interpolated.equals( value ) ) { try { diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java index 02c7c889c5d5..32646304f6d5 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java @@ -1424,7 +1424,7 @@ private void visit( Properties properties ) { String value = (String) v; String inter = interpolate( value ); - if ( value != inter ) + if ( value != inter && inter != null ) { entry.setValue( inter ); } 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/DefaultProfileActivationContext.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileActivationContext.java index 77d92a377c40..4fb1b265e3ec 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileActivationContext.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileActivationContext.java @@ -21,12 +21,13 @@ import java.io.File; import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.toMap; + /** * Describes the environmental context used to determine the activation status of profiles. * @@ -230,8 +231,11 @@ public DefaultProfileActivationContext setProjectProperties( Properties projectP { if ( projectProperties != null ) { - - this.projectProperties = Collections.unmodifiableMap( toMap( projectProperties ) ); + this.projectProperties = projectProperties.entrySet().stream() + .collect( + collectingAndThen( + toMap( k -> String.valueOf( k.getKey() ), v -> String.valueOf( v ) ), + Collections::unmodifiableMap ) ); } else { @@ -241,19 +245,4 @@ public DefaultProfileActivationContext setProjectProperties( Properties projectP return this; } - private Map toMap( Properties properties ) - { - if ( properties == null ) - { - return Collections.emptyMap(); - } - Map map = new HashMap<>(); - Enumeration keys = properties.keys(); - while ( keys.hasMoreElements() ) - { - String key = (String) keys.nextElement(); - map.put( key, properties.getProperty( key ) ); - } - return map; - } } 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/main/java/org/apache/maven/model/validation/DefaultModelValidator.java b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java index cfa6e20f6cdc..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; @@ -53,10 +53,12 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; @@ -71,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; @@ -86,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 ) { @@ -527,12 +532,12 @@ else if ( sysPath.contains( "${basedir}" ) || sysPath.contains( "${project.based if ( equals( existing.getVersion(), dependency.getVersion() ) ) { msg = "duplicate declaration of version " - + StringUtils.defaultString( dependency.getVersion(), "(?)" ); + + Objects.toString( dependency.getVersion(), "(?)" ); } else { - msg = "version " + StringUtils.defaultString( existing.getVersion(), "(?)" ) + " vs " - + StringUtils.defaultString( dependency.getVersion(), "(?)" ); + msg = "version " + Objects.toString( existing.getVersion(), "(?)" ) + " vs " + + Objects.toString( dependency.getVersion(), "(?)" ); } addViolation( problems, errOn31, Version.V20, prefix + prefix2 + "(groupId:artifactId:type:classifier)", @@ -929,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/site/apt/index.apt b/maven-model-builder/src/site/apt/index.apt index e18ad9deb331..f7dd1d2e038c 100644 --- a/maven-model-builder/src/site/apt/index.apt +++ b/maven-model-builder/src/site/apt/index.apt @@ -81,7 +81,7 @@ Maven Model Builder with its <<>> implementation in maven-core ({{{./maven-core/xref/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.html}source}}) - ** dependency management import (for dependencies of type <<>> in the <<<\>>> section) + ** dependency management import (for dependencies of type <<>> and scope <<>> in the <<<\>>> section) ** dependency management injection: <<>> ({{{./apidocs/org/apache/maven/model/management/DependencyManagementInjector.html}javadoc}}), with its <<>> implementation 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/building/DefaultModelBuilderTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java new file mode 100644 index 000000000000..4e7919a6c2ed --- /dev/null +++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java @@ -0,0 +1,153 @@ +package org.apache.maven.model.building; + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Parent; +import org.apache.maven.model.Repository; +import org.apache.maven.model.resolution.InvalidRepositoryException; +import org.apache.maven.model.resolution.ModelResolver; +import org.apache.maven.model.resolution.UnresolvableModelException; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +/** + * @author Guillaume Nodet + */ +public class DefaultModelBuilderTest +{ + + private static final String BASE1_ID = "thegroup:base1:pom"; + private static final String BASE1_ID2 = "thegroup:base1:1"; + + private static final String BASE1 = "\n" + + " 4.0.0\n" + + " thegroup\n" + + " base1\n" + + " 1\n" + + " pom\n" + + " \n" + + " \n" + + " \n" + + " thegroup\n" + + " base2\n" + + " 1\n" + + " pom\n" + + " import\n" + + " \n" + + " \n" + + " \n" + + "\n"; + + private static final String BASE2_ID = "thegroup:base2:pom"; + private static final String BASE2_ID2 = "thegroup:base2:1"; + + private static final String BASE2 = "\n" + + " 4.0.0\n" + + " thegroup\n" + + " base2\n" + + " 1\n" + + " pom\n" + + " \n" + + " \n" + + " \n" + + " thegroup\n" + + " base1\n" + + " 1\n" + + " pom\n" + + " import\n" + + " \n" + + " \n" + + " \n" + + "\n"; + + @Test( expected = ModelBuildingException.class ) + public void testCycleInImports() + throws Exception + { + ModelBuilder builder = new DefaultModelBuilderFactory().newInstance(); + assertNotNull( builder ); + + DefaultModelBuildingRequest request = new DefaultModelBuildingRequest(); + request.setModelSource( new StringModelSource( BASE1 ) ); + request.setModelResolver( new CycleInImportsResolver() ); + + builder.build( request ); + } + + static class CycleInImportsResolver extends BaseModelResolver + { + @Override + public ModelSource resolveModel(Dependency dependency) throws UnresolvableModelException + { + switch ( dependency.getManagementKey() ) + { + case BASE1_ID: return new StringModelSource( BASE1 ); + case BASE2_ID: return new StringModelSource( BASE2 ); + } + return null; + } + } + + static class BaseModelResolver implements ModelResolver + { + @Override + public ModelSource resolveModel( String groupId, String artifactId, String version ) + throws UnresolvableModelException + { + switch ( groupId + ":" + artifactId + ":" + version ) + { + case BASE1_ID2: return new StringModelSource( BASE1 ); + case BASE2_ID2: return new StringModelSource( BASE2 ); + } + return null; + } + + @Override + public ModelSource resolveModel( Parent parent ) throws UnresolvableModelException + { + return null; + } + + @Override + public ModelSource resolveModel( Dependency dependency ) throws UnresolvableModelException + { + return null; + } + + @Override + public void addRepository( Repository repository ) throws InvalidRepositoryException + { + } + + @Override + public void addRepository(Repository repository, boolean replace) throws InvalidRepositoryException + { + } + + @Override + public ModelResolver newCopy() + { + return this; + } + } + +} diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java index 9b0ecd9ddf57..6c8ebe0e4220 100644 --- a/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java +++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java @@ -22,7 +22,7 @@ import java.io.IOException; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertTrue; -import org.apache.commons.lang3.SystemUtils; +import org.codehaus.plexus.util.Os;; import static org.junit.Assume.assumeTrue; import org.junit.Test; @@ -53,7 +53,7 @@ public void testEquals() public void testWindowsPaths() throws Exception { - assumeTrue( SystemUtils.IS_OS_WINDOWS ); + assumeTrue( Os.isFamily( "Windows" ) ); File upperCaseFile = createTempFile( "TESTE" ); String absolutePath = upperCaseFile.getAbsolutePath(); diff --git a/maven-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 b66abcade2a9..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() ); } @@ -365,7 +366,7 @@ public void testInterpolateObjectWithPomFile() interpolator.interpolateObject( obj, model, new File( "." ), config, collector ); assertProblemFree( collector ); - assertThat( baseDir.getCanonicalPath(), is( System.getProperty( "user.dir" ) ) ); + assertThat( baseDir.getAbsolutePath(), is( System.getProperty( "user.dir" ) ) ); assertThat( obj.values.size(), is( 1 ) ); assertThat( (String) obj.values.get( "key" ), is( anyOf( is( System.getProperty( "user.dir" ) + File.separator + "target" ), @@ -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/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; + } +} 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 diff --git a/maven-model/pom.xml b/maven-model/pom.xml index f9f015349e2c..702c9858cd36 100644 --- a/maven-model/pom.xml +++ b/maven-model/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.6.3 + 3.9.0-SNAPSHOT maven-model @@ -82,46 +82,4 @@ under the License. - - - all-models - - - - org.codehaus.modello - modello-maven-plugin - - - v3 - - java - xpp3-writer - xpp3-reader - xsd - - - 3.0.0 - true - - - - - - maven-jar-plugin - - - package - - jar - - - all - - - - - - - - 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/main/mdo/maven.mdo b/maven-model/src/main/mdo/maven.mdo index 1f1f9d1864d9..00bf3d51adef 100644 --- a/maven-model/src/main/mdo/maven.mdo +++ b/maven-model/src/main/mdo/maven.mdo @@ -43,8 +43,8 @@ | definition of these types | --> - maven @@ -642,11 +642,11 @@ - + BuildBase 3.0.0+ PluginConfiguration - Generic informations for a build. + Build configuration in a profile. defaultGoal @@ -1191,16 +1191,16 @@ - artifactId + groupId 4.0.0+ - The artifact ID of the project to exclude. + The group ID of the project to exclude. String true - groupId + artifactId 4.0.0+ - The group ID of the project to exclude. + The artifact ID of the project to exclude. String true @@ -1937,12 +1937,12 @@ - + DeploymentRepository Repository 4.0.0+ - Repository contains the information needed for deploying to the remote - repository. + Deployment repository contains the information needed for deploying to the remote + repository, which adds uniqueVersion property to usual repositories for download. uniqueVersion @@ -2314,18 +2314,12 @@ return id.toString(); } - //TODO we shall reset key variable when groupId/artifactId change - private String key = null; /** * @return the key of the plugin, ie groupId:artifactId */ public String getKey() { - if ( key == null ) - { - key = constructKey( groupId, artifactId ); - } - return key; + return constructKey( groupId, artifactId ); } /** @@ -2813,13 +2807,13 @@ --> - + ReportPlugin 4.0.0+ ConfigurationContainer <plugin> element contains informations required for a report plugin. + The <plugin> element in <reporting><plugins> contains informations required for a report plugin. ]]> @@ -2841,7 +2835,12 @@ version 4.0.0+ - The version of the reporting plugin to be used. + + build/plugins then in build/pluginManagement. + ]]> + String 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 diff --git a/maven-plugin-api/pom.xml b/maven-plugin-api/pom.xml index 8abe7430d673..4f94861ff4c4 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.6.3 + 3.9.0-SNAPSHOT maven-plugin-api diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java index 52aded3d654d..e8df3095f212 100644 --- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java +++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java @@ -41,6 +41,18 @@ public AbstractMojoExecutionException( String message, Throwable cause ) super( message, cause ); } + /** + * Constructs a new {@code AbstractMojoExecutionException} exception wrapping an underlying {@code Throwable}. + * + * @param cause the cause which is saved for later retrieval by the {@link #getCause()} method. + * A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 3.8.3 + */ + public AbstractMojoExecutionException( Throwable cause ) + { + super( cause ); + } + public String getLongMessage() { return longMessage; diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java index 4d8c416e077d..6d089898600c 100644 --- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java +++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java @@ -76,4 +76,17 @@ public MojoExecutionException( String message ) { super( message ); } + + /** + * Constructs a new {@code MojoExecutionException} exception wrapping an underlying {@code Throwable}. + * + * @param cause the cause which is saved for later retrieval by the {@link #getCause()} method. + * A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 3.8.3 + */ + public MojoExecutionException( Throwable cause ) + { + super( cause ); + } + } diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java index 342d081f00b2..72faec679eb9 100644 --- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java +++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java @@ -65,4 +65,17 @@ public MojoFailureException( String message, Throwable cause ) { super( message, cause ); } + + /** + * Constructs a new {@code MojoFailureException} exception wrapping an underlying {@code Throwable}. + * + * @param cause the cause which is saved for later retrieval by the {@link #getCause()} method. + * A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown. + * @since 3.8.3 + */ + public MojoFailureException( Throwable cause ) + { + super( cause ); + } + } diff --git a/maven-repository-metadata/pom.xml b/maven-repository-metadata/pom.xml index 07a0a177c5a8..7567df5f6b82 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.6.3 + 3.9.0-SNAPSHOT maven-repository-metadata @@ -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 e2d07533972d..6ce381d4a830 100644 --- a/maven-repository-metadata/src/main/mdo/metadata.mdo +++ b/maven-repository-metadata/src/main/mdo/metadata.mdo @@ -20,15 +20,13 @@ under the License. + xml.schemaLocation="https://maven.apache.org/xsd/repository-metadata-${version}.xsd"> 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 * @@ -87,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; + } } } } @@ -213,47 +250,47 @@ 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). The timestamp is expressed using UTC in the format yyyyMMddHHmmss. + + + snapshot + 1.0.0+ + + Snapshot + + The current snapshot data in use for this version ("groupId/artifactId/version" only) 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 * @@ -283,12 +320,12 @@ 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 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 @@ -315,33 +352,41 @@ 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 thesub-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 + 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 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 diff --git a/maven-resolver-provider/pom.xml b/maven-resolver-provider/pom.xml index aad87452c748..d273a738ff8e 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.6.3 + 3.9.0-SNAPSHOT maven-resolver-provider @@ -80,8 +80,22 @@ under the License. aopalliance aopalliance + + com.google.guava + guava + + + com.google.guava + guava + true + + + com.google.guava + failureaccess + true + org.apache.maven.resolver @@ -90,12 +104,12 @@ under the License. org.apache.maven.resolver - maven-resolver-transport-wagon + maven-resolver-transport-file test - org.apache.maven.wagon - wagon-file + org.apache.maven.resolver + maven-resolver-transport-http test @@ -108,10 +122,6 @@ under the License. mockito-core test - - org.slf4j - slf4j-api - org.slf4j slf4j-simple 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 586c83e271e9..9e56b03b7c60 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 @@ -89,6 +89,8 @@ public class DefaultArtifactDescriptorReader private ModelBuilder modelBuilder; + private ModelCacheFactory modelCacheFactory; + public DefaultArtifactDescriptorReader() { // enable no-arg constructor @@ -97,7 +99,8 @@ public DefaultArtifactDescriptorReader() @Inject DefaultArtifactDescriptorReader( RemoteRepositoryManager remoteRepositoryManager, VersionResolver versionResolver, VersionRangeResolver versionRangeResolver, ArtifactResolver artifactResolver, - ModelBuilder modelBuilder, RepositoryEventDispatcher repositoryEventDispatcher ) + ModelBuilder modelBuilder, RepositoryEventDispatcher repositoryEventDispatcher, + ModelCacheFactory modelCacheFactory ) { setRemoteRepositoryManager( remoteRepositoryManager ); setVersionResolver( versionResolver ); @@ -105,6 +108,7 @@ public DefaultArtifactDescriptorReader() setArtifactResolver( artifactResolver ); setModelBuilder( modelBuilder ); setRepositoryEventDispatcher( repositoryEventDispatcher ); + setModelCacheFactory( modelCacheFactory ); } public void initService( ServiceLocator locator ) @@ -119,6 +123,7 @@ public void initService( ServiceLocator locator ) setModelBuilder( new DefaultModelBuilderFactory().newInstance() ); } setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) ); + setModelCacheFactory( locator.getService( ModelCacheFactory.class ) ); } public DefaultArtifactDescriptorReader setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager ) @@ -162,6 +167,13 @@ public DefaultArtifactDescriptorReader setModelBuilder( ModelBuilder modelBuilde return this; } + public DefaultArtifactDescriptorReader setModelCacheFactory( ModelCacheFactory modelCacheFactory ) + { + this.modelCacheFactory = Objects.requireNonNull( modelCacheFactory, + "modelCacheFactory cannot be null" ); + return this; + } + public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session, ArtifactDescriptorRequest request ) throws ArtifactDescriptorException @@ -257,6 +269,7 @@ private Model loadPom( RepositorySystemSession session, ArtifactDescriptorReques Model model; + // TODO hack: don't rebuild model if it was already loaded during reactor resolution final WorkspaceReader workspace = session.getWorkspaceReader(); if ( workspace instanceof MavenWorkspaceReader ) { @@ -273,9 +286,9 @@ 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.setModelCache( DefaultModelCache.newInstance( session ) ); + modelRequest.setSystemProperties( toProperties( session.getSystemProperties() ) ); + modelRequest.setUserProperties( toProperties( session.getUserProperties() ) ); + modelRequest.setModelCache( modelCacheFactory.createCache( session ) ); modelRequest.setModelResolver( new DefaultModelResolver( session, trace.newChild( modelRequest ), request.getRequestContext(), artifactResolver, versionRangeResolver, remoteRepositoryManager, @@ -317,7 +330,7 @@ private Model loadPom( RepositorySystemSession session, ArtifactDescriptorReques result.addRelocation( a ); a = new RelocatedArtifact( a, relocation.getGroupId(), relocation.getArtifactId(), - relocation.getVersion() ); + relocation.getVersion(), relocation.getMessage() ); result.setArtifact( a ); } else @@ -327,17 +340,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; } diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCacheFactory.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCacheFactory.java new file mode 100644 index 000000000000..785a4e023582 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCacheFactory.java @@ -0,0 +1,41 @@ +package org.apache.maven.repository.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.Named; +import javax.inject.Singleton; + +import org.apache.maven.model.building.ModelCache; +import org.eclipse.aether.RepositorySystemSession; + +/** + * Default implementation of {@link ModelCacheFactory}. + */ +@Singleton +@Named +public class DefaultModelCacheFactory implements ModelCacheFactory +{ + @Override + public ModelCache createCache( RepositorySystemSession session ) + { + return DefaultModelCache.newInstance( session ); + } + +} diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java index 83c82a038598..d870fbb951f4 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java @@ -28,7 +28,6 @@ import org.eclipse.aether.SyncContext; import org.eclipse.aether.impl.MetadataResolver; import org.eclipse.aether.impl.RepositoryEventDispatcher; -import org.eclipse.aether.impl.SyncContextFactory; import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.metadata.DefaultMetadata; import org.eclipse.aether.metadata.Metadata; @@ -42,6 +41,7 @@ import org.eclipse.aether.resolution.VersionRangeResult; import org.eclipse.aether.spi.locator.Service; import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.synccontext.SyncContextFactory; import org.eclipse.aether.util.version.GenericVersionScheme; import org.eclipse.aether.version.InvalidVersionSpecificationException; import org.eclipse.aether.version.Version; diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java index d307c55a69f1..9f1680726c17 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java @@ -33,7 +33,6 @@ import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.impl.MetadataResolver; import org.eclipse.aether.impl.RepositoryEventDispatcher; -import org.eclipse.aether.impl.SyncContextFactory; import org.eclipse.aether.impl.VersionResolver; import org.eclipse.aether.metadata.DefaultMetadata; import org.eclipse.aether.metadata.Metadata; @@ -49,6 +48,7 @@ import org.eclipse.aether.resolution.VersionResult; import org.eclipse.aether.spi.locator.Service; import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.synccontext.SyncContextFactory; import org.eclipse.aether.util.ConfigUtils; import javax.inject.Inject; diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java index ce09efdf4f31..453e4d2bec9d 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java @@ -22,6 +22,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; @@ -42,15 +43,15 @@ final class LocalSnapshotMetadata private final boolean legacyFormat; - LocalSnapshotMetadata( Artifact artifact, boolean legacyFormat ) + LocalSnapshotMetadata( Artifact artifact, boolean legacyFormat, Date timestamp ) { - super( createMetadata( artifact, legacyFormat ), null ); + super( createMetadata( artifact, legacyFormat ), null, timestamp ); this.legacyFormat = legacyFormat; } - LocalSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat ) + LocalSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat, Date timestamp ) { - super( metadata, file ); + super( metadata, file, timestamp ); this.legacyFormat = legacyFormat; } @@ -82,7 +83,7 @@ public void bind( Artifact artifact ) public MavenMetadata setFile( File file ) { - return new LocalSnapshotMetadata( metadata, file, legacyFormat ); + return new LocalSnapshotMetadata( metadata, file, legacyFormat, timestamp ); } public Object getKey() @@ -98,7 +99,7 @@ public static Object getKey( Artifact artifact ) @Override protected void merge( Metadata recessive ) { - metadata.getVersioning().updateTimestamp(); + metadata.getVersioning().setLastUpdatedTimestamp( timestamp ); if ( !legacyFormat ) { @@ -160,4 +161,4 @@ public Nature getNature() return Nature.SNAPSHOT; } -} \ No newline at end of file +} diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java index 584e1666064e..75b4e6b93900 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; @@ -42,10 +43,14 @@ class LocalSnapshotMetadataGenerator private final boolean legacyFormat; + private final Date timestamp; + LocalSnapshotMetadataGenerator( RepositorySystemSession session, InstallRequest request ) { legacyFormat = ConfigUtils.getBoolean( session.getConfigProperties(), false, "maven.metadata.legacy" ); + timestamp = (Date) ConfigUtils.getObject( session, new Date(), "maven.startTime" ); + snapshots = new LinkedHashMap<>(); } @@ -59,7 +64,7 @@ public Collection prepare( Collection ar LocalSnapshotMetadata snapshotMetadata = snapshots.get( key ); if ( snapshotMetadata == null ) { - snapshotMetadata = new LocalSnapshotMetadata( artifact, legacyFormat ); + snapshotMetadata = new LocalSnapshotMetadata( artifact, legacyFormat, timestamp ); snapshots.put( key, snapshotMetadata ); } snapshotMetadata.bind( artifact ); diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenAetherModule.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenAetherModule.java deleted file mode 100644 index 41e98aaea8ae..000000000000 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenAetherModule.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.apache.maven.repository.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 java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import javax.inject.Named; -import javax.inject.Singleton; - -import org.apache.maven.model.building.DefaultModelBuilderFactory; -import org.apache.maven.model.building.ModelBuilder; -import org.eclipse.aether.impl.AetherModule; -import org.eclipse.aether.impl.ArtifactDescriptorReader; -import org.eclipse.aether.impl.MetadataGeneratorFactory; -import org.eclipse.aether.impl.VersionRangeResolver; -import org.eclipse.aether.impl.VersionResolver; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.name.Names; - -/** - * @deprecated As of Maven Resolver 1.0.3, please use class {@link MavenResolverModule}. - */ -@Deprecated -public final class MavenAetherModule - extends AbstractModule -{ - - @Override - protected void configure() - { - install( new AetherModule() ); - bind( ArtifactDescriptorReader.class ) // - .to( DefaultArtifactDescriptorReader.class ).in( Singleton.class ); - bind( VersionResolver.class ) // - .to( DefaultVersionResolver.class ).in( Singleton.class ); - bind( VersionRangeResolver.class ) // - .to( DefaultVersionRangeResolver.class ).in( Singleton.class ); - bind( MetadataGeneratorFactory.class ).annotatedWith( Names.named( "snapshot" ) ) // - .to( SnapshotMetadataGeneratorFactory.class ).in( Singleton.class ); - bind( MetadataGeneratorFactory.class ).annotatedWith( Names.named( "versions" ) ) // - .to( VersionsMetadataGeneratorFactory.class ).in( Singleton.class ); - bind( ModelBuilder.class ) // - .toInstance( new DefaultModelBuilderFactory().newInstance() ); - } - - @Provides - @Singleton - Set provideMetadataGeneratorFactories( @Named( "snapshot" ) - MetadataGeneratorFactory snapshot, - @Named( "versions" ) - MetadataGeneratorFactory versions ) - { - Set factories = new HashSet<>(); - factories.add( snapshot ); - factories.add( versions ); - return Collections.unmodifiableSet( factories ); - } - -} diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java index aef44f6bbb5e..bdddc709f6ae 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java @@ -34,6 +34,7 @@ import java.io.Reader; import java.io.Writer; import java.util.Collections; +import java.util.Date; import java.util.Map; /** @@ -46,16 +47,19 @@ abstract class MavenMetadata static final String MAVEN_METADATA_XML = "maven-metadata.xml"; + protected Metadata metadata; + private final File file; - protected Metadata metadata; + protected final Date timestamp; private boolean merged; - protected MavenMetadata( Metadata metadata, File file ) + protected MavenMetadata( Metadata metadata, File file, Date timestamp ) { this.metadata = metadata; this.file = file; + this.timestamp = timestamp; } public String getType() diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java index 97035b3cc821..8fa3767f7a29 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java @@ -68,7 +68,9 @@ private MavenRepositorySystemUtils() * acquire a complete repository system, clients need to add some repository connectors for remote transfers. * * @return The new service locator, never {@code null}. + * @deprecated This method is deprecated along with {@link DefaultServiceLocator} (since Maven Resolver 1.7.0). */ + @Deprecated public static DefaultServiceLocator newServiceLocator() { DefaultServiceLocator locator = new DefaultServiceLocator(); @@ -77,6 +79,7 @@ public static DefaultServiceLocator newServiceLocator() locator.addService( VersionRangeResolver.class, DefaultVersionRangeResolver.class ); locator.addService( MetadataGeneratorFactory.class, SnapshotMetadataGeneratorFactory.class ); locator.addService( MetadataGeneratorFactory.class, VersionsMetadataGeneratorFactory.class ); + locator.addService( ModelCacheFactory.class, DefaultModelCacheFactory.class ); return locator; } diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java index 1e49bfce3586..c7120c99a46d 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java @@ -56,6 +56,7 @@ protected void configure() .to( VersionsMetadataGeneratorFactory.class ).in( Singleton.class ); bind( ModelBuilder.class ).toInstance( new DefaultModelBuilderFactory().newInstance() ); + bind( ModelCacheFactory.class ).to( DefaultModelCacheFactory.class ).in( Singleton.class ); } @Provides diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java index e4c9a7e9e0d7..35d4d42808a1 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java @@ -22,6 +22,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import org.apache.maven.artifact.repository.metadata.Metadata; import org.eclipse.aether.artifact.Artifact; @@ -38,9 +39,9 @@ abstract class MavenSnapshotMetadata protected final boolean legacyFormat; - protected MavenSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat ) + protected MavenSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat, Date timestamp ) { - super( metadata, file ); + super( metadata, file, timestamp ); this.legacyFormat = legacyFormat; } diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ModelCacheFactory.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ModelCacheFactory.java new file mode 100644 index 000000000000..0e4299042ed2 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ModelCacheFactory.java @@ -0,0 +1,33 @@ +package org.apache.maven.repository.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.model.building.ModelCache; +import org.eclipse.aether.RepositorySystemSession; + +/** + * Factory for {@link ModelCache} objects. + */ +public interface ModelCacheFactory +{ + + ModelCache createCache( RepositorySystemSession session ); + +} diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadata.java new file mode 100644 index 000000000000..7a6c45abfe79 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadata.java @@ -0,0 +1,117 @@ +package org.apache.maven.repository.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 java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.List; + +import org.apache.maven.artifact.repository.metadata.Metadata; +import org.apache.maven.artifact.repository.metadata.Plugin; +import org.apache.maven.repository.internal.PluginsMetadataInfoProvider.PluginInfo; +import org.eclipse.aether.artifact.Artifact; + +/** + * Plugin G level metadata. + */ +final class PluginsMetadata + extends MavenMetadata +{ + private final PluginInfo pluginInfo; + + PluginsMetadata( PluginInfo pluginInfo, Date timestamp ) + { + super( createRepositoryMetadata( pluginInfo ), null, timestamp ); + this.pluginInfo = pluginInfo; + } + + PluginsMetadata( PluginInfo pluginInfo, File file, Date timestamp ) + { + super( createRepositoryMetadata( pluginInfo ), file, timestamp ); + this.pluginInfo = pluginInfo; + } + + private static Metadata createRepositoryMetadata( PluginInfo pluginInfo ) + { + Metadata result = new Metadata(); + Plugin plugin = new Plugin(); + plugin.setPrefix( pluginInfo.getPluginPrefix() ); + plugin.setArtifactId( pluginInfo.getPluginArtifactId() ); + plugin.setName( pluginInfo.getPluginName() ); + result.getPlugins().add( plugin ); + return result; + } + + @Override + protected void merge( Metadata recessive ) + { + List recessivePlugins = recessive.getPlugins(); + List plugins = metadata.getPlugins(); + if ( !plugins.isEmpty() ) + { + LinkedHashMap mergedPlugins = new LinkedHashMap<>(); + recessivePlugins.forEach( p -> mergedPlugins.put( p.getPrefix(), p ) ); + plugins.forEach( p -> mergedPlugins.put( p.getPrefix(), p ) ); + metadata.setPlugins( new ArrayList<>( mergedPlugins.values() ) ); + } + } + + public Object getKey() + { + return getGroupId(); + } + + public static Object getKey( Artifact artifact ) + { + return artifact.getGroupId(); + } + + @Override + public MavenMetadata setFile( File file ) + { + return new PluginsMetadata( pluginInfo, file, timestamp ); + } + + @Override + public String getGroupId() + { + return pluginInfo.getPluginGroupId(); + } + + @Override + public String getArtifactId() + { + return ""; + } + + @Override + public String getVersion() + { + return ""; + } + + @Override + public Nature getNature() + { + return Nature.RELEASE_OR_SNAPSHOT; + } +} diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGenerator.java new file mode 100644 index 000000000000..4f355686517c --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGenerator.java @@ -0,0 +1,130 @@ +package org.apache.maven.repository.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 java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.maven.repository.internal.PluginsMetadataInfoProvider.PluginInfo; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.impl.MetadataGenerator; +import org.eclipse.aether.installation.InstallRequest; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.util.ConfigUtils; + +import static java.util.Objects.requireNonNull; + +/** + * Plugin G level metadata. + */ +class PluginsMetadataGenerator + implements MetadataGenerator +{ + private final PluginsMetadataInfoProvider pluginsMetadataInfoProvider; + + private final Map plugins; + + private final Map processedPlugins; + + private final Date timestamp; + + PluginsMetadataGenerator( PluginsMetadataInfoProvider pluginsMetadataInfoProvider, + RepositorySystemSession session, + InstallRequest request ) + { + this( pluginsMetadataInfoProvider, session, request.getMetadata() ); + } + + PluginsMetadataGenerator( PluginsMetadataInfoProvider pluginsMetadataInfoProvider, + RepositorySystemSession session, + DeployRequest request ) + { + this( pluginsMetadataInfoProvider, session, request.getMetadata() ); + } + + private PluginsMetadataGenerator( PluginsMetadataInfoProvider pluginsMetadataInfoProvider, + RepositorySystemSession session, + Collection metadatas ) + { + this.pluginsMetadataInfoProvider = requireNonNull( pluginsMetadataInfoProvider ); + this.plugins = new LinkedHashMap<>(); + this.processedPlugins = new LinkedHashMap<>(); + this.timestamp = (Date) ConfigUtils.getObject( session, new Date(), "maven.startTime" ); + + /* + * NOTE: This should be considered a quirk to support interop with Maven's legacy ArtifactDeployer which + * processes one artifact at a time and hence cannot associate the artifacts from the same project to use the + * same version index. Allowing the caller to pass in metadata from a previous deployment allows to re-establish + * the association between the artifacts of the same project. + */ + for ( Iterator it = metadatas.iterator(); it.hasNext(); ) + { + Metadata metadata = it.next(); + if ( metadata instanceof PluginsMetadata ) + { + it.remove(); + PluginsMetadata pluginMetadata = ( PluginsMetadata ) metadata; + processedPlugins.put( pluginMetadata.getKey(), pluginMetadata ); + } + } + } + + @Override + public Collection prepare( Collection artifacts ) + { + return Collections.emptyList(); + } + + @Override + public Artifact transformArtifact( Artifact artifact ) + { + return artifact; + } + + @Override + public Collection finish( Collection artifacts ) + { + for ( Artifact artifact : artifacts ) + { + PluginInfo pluginInfo = pluginsMetadataInfoProvider.getPluginInfo( artifact ); + if ( pluginInfo != null ) + { + Object key = PluginsMetadata.getKey( artifact ); + if ( processedPlugins.get( key ) == null ) + { + PluginsMetadata pluginMetadata = plugins.get( key ); + if ( pluginMetadata == null ) + { + pluginMetadata = new PluginsMetadata( pluginInfo, timestamp ); + plugins.put( key, pluginMetadata ); + } + } + } + } + + return plugins.values(); + } +} diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory.java new file mode 100644 index 000000000000..19d499b25772 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory.java @@ -0,0 +1,67 @@ +package org.apache.maven.repository.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.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.impl.MetadataGenerator; +import org.eclipse.aether.impl.MetadataGeneratorFactory; +import org.eclipse.aether.installation.InstallRequest; + +import static java.util.Objects.requireNonNull; + +/** + * Plugin G level metadata. + */ +@Named( "plugins" ) +@Singleton +public class PluginsMetadataGeneratorFactory + implements MetadataGeneratorFactory +{ + private final PluginsMetadataInfoProvider pluginsMetadataInfoProvider; + + @Inject + public PluginsMetadataGeneratorFactory( PluginsMetadataInfoProvider pluginsMetadataInfoProvider ) + { + this.pluginsMetadataInfoProvider = requireNonNull( pluginsMetadataInfoProvider ); + } + + @Override + public MetadataGenerator newInstance( RepositorySystemSession session, InstallRequest request ) + { + return new PluginsMetadataGenerator( pluginsMetadataInfoProvider, session, request ); + } + + @Override + public MetadataGenerator newInstance( RepositorySystemSession session, DeployRequest request ) + { + return new PluginsMetadataGenerator( pluginsMetadataInfoProvider, session, request ); + } + + @Override + public float getPriority() + { + return 5; + } +} diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataInfoProvider.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataInfoProvider.java new file mode 100644 index 000000000000..806fa46348be --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataInfoProvider.java @@ -0,0 +1,47 @@ +package org.apache.maven.repository.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.eclipse.aether.artifact.Artifact; + +/** + * Plugin G level metadata provider. + */ +public interface PluginsMetadataInfoProvider +{ + /** + * The required data for G level metadata. + */ + interface PluginInfo + { + String getPluginGroupId(); + + String getPluginArtifactId(); + + String getPluginPrefix(); + + String getPluginName(); + } + + /** + * Returns {@link PluginInfo} corresponding for passed in {@link Artifact}, or {@code null}. + */ + PluginInfo getPluginInfo( Artifact artifact ); +} 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..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() @@ -86,6 +89,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, message ); + } + + @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, message ); + } + + @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, message ); + } + public String getClassifier() { return artifact.getClassifier(); @@ -111,4 +148,8 @@ public Map getProperties() return artifact.getProperties(); } + public String getMessage() + { + return message; + } } diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java index efcfb4d5e8ca..d9b56166af79 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java @@ -47,19 +47,19 @@ final class RemoteSnapshotMetadata private final Map versions = new LinkedHashMap<>(); - RemoteSnapshotMetadata( Artifact artifact, boolean legacyFormat ) + RemoteSnapshotMetadata( Artifact artifact, boolean legacyFormat, Date timestamp ) { - super( createRepositoryMetadata( artifact, legacyFormat ), null, legacyFormat ); + super( createRepositoryMetadata( artifact, legacyFormat ), null, legacyFormat, timestamp ); } - private RemoteSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat ) + private RemoteSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat, Date timestamp ) { - super( metadata, file, legacyFormat ); + super( metadata, file, legacyFormat, timestamp ); } public MavenMetadata setFile( File file ) { - return new RemoteSnapshotMetadata( metadata, file, legacyFormat ); + return new RemoteSnapshotMetadata( metadata, file, legacyFormat, timestamp ); } public String getExpandedVersion( Artifact artifact ) @@ -82,11 +82,11 @@ protected void merge( Metadata recessive ) snapshot = new Snapshot(); snapshot.setBuildNumber( getBuildNumber( recessive ) + 1 ); - snapshot.setTimestamp( utcDateFormatter.format( new Date() ) ); + snapshot.setTimestamp( utcDateFormatter.format( timestamp ) ); Versioning versioning = new Versioning(); versioning.setSnapshot( snapshot ); - versioning.setLastUpdated( snapshot.getTimestamp().replace( ".", "" ) ); + versioning.setLastUpdatedTimestamp( timestamp ); lastUpdated = versioning.getLastUpdated(); metadata.setVersioning( versioning ); diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java index 32188636b34a..2e42bee7d5c7 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; @@ -42,9 +43,13 @@ class RemoteSnapshotMetadataGenerator private final boolean legacyFormat; + private final Date timestamp; + RemoteSnapshotMetadataGenerator( RepositorySystemSession session, DeployRequest request ) { - legacyFormat = ConfigUtils.getBoolean( session.getConfigProperties(), false, "maven.metadata.legacy" ); + legacyFormat = ConfigUtils.getBoolean( session, false, "maven.metadata.legacy" ); + + timestamp = (Date) ConfigUtils.getObject( session, new Date(), "maven.startTime" ); snapshots = new LinkedHashMap<>(); @@ -74,7 +79,7 @@ public Collection prepare( Collection ar RemoteSnapshotMetadata snapshotMetadata = snapshots.get( key ); if ( snapshotMetadata == null ) { - snapshotMetadata = new RemoteSnapshotMetadata( artifact, legacyFormat ); + snapshotMetadata = new RemoteSnapshotMetadata( artifact, legacyFormat, timestamp ); snapshots.put( key, snapshotMetadata ); } snapshotMetadata.bind( artifact ); diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java index f7df64ef7fa9..5103e5caea82 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java @@ -22,6 +22,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import java.util.LinkedHashSet; import org.apache.maven.artifact.repository.metadata.Metadata; @@ -38,15 +39,15 @@ final class VersionsMetadata private final Artifact artifact; - VersionsMetadata( Artifact artifact ) + VersionsMetadata( Artifact artifact, Date timestamp ) { - super( createRepositoryMetadata( artifact ), null ); + super( createRepositoryMetadata( artifact ), null, timestamp ); this.artifact = artifact; } - VersionsMetadata( Artifact artifact, File file ) + VersionsMetadata( Artifact artifact, File file, Date timestamp ) { - super( createRepositoryMetadata( artifact ), file ); + super( createRepositoryMetadata( artifact ), file, timestamp ); this.artifact = artifact; } @@ -76,7 +77,7 @@ private static Metadata createRepositoryMetadata( Artifact artifact ) protected void merge( Metadata recessive ) { Versioning versioning = metadata.getVersioning(); - versioning.updateTimestamp(); + versioning.setLastUpdatedTimestamp( timestamp ); if ( recessive.getVersioning() != null ) { @@ -107,7 +108,7 @@ public static Object getKey( Artifact artifact ) public MavenMetadata setFile( File file ) { - return new VersionsMetadata( artifact, file ); + return new VersionsMetadata( artifact, file, timestamp ); } public String getGroupId() diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java index d6b5c8a41c91..409eec4221d1 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; @@ -31,6 +32,7 @@ import org.eclipse.aether.impl.MetadataGenerator; import org.eclipse.aether.installation.InstallRequest; import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.util.ConfigUtils; /** * @author Benjamin Bentmann @@ -43,6 +45,8 @@ class VersionsMetadataGenerator private Map processedVersions; + private final Date timestamp; + VersionsMetadataGenerator( RepositorySystemSession session, InstallRequest request ) { this( session, request.getMetadata() ); @@ -57,6 +61,7 @@ private VersionsMetadataGenerator( RepositorySystemSession session, Collection(); processedVersions = new LinkedHashMap<>(); + timestamp = (Date) ConfigUtils.getObject( session, new Date(), "maven.startTime" ); /* * NOTE: This should be considered a quirk to support interop with Maven's legacy ArtifactDeployer which @@ -96,7 +101,7 @@ public Collection finish( Collection art VersionsMetadata versionsMetadata = versions.get( key ); if ( versionsMetadata == null ) { - versionsMetadata = new VersionsMetadata( artifact ); + versionsMetadata = new VersionsMetadata( artifact, timestamp ); versions.put( key, versionsMetadata ); } } diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java index 278231f9f60e..c319348c8082 100644 --- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java +++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java @@ -66,7 +66,7 @@ public void gregorianCalendarIsUsed() String dateBefore = gregorianDate(); RemoteSnapshotMetadata metadata = new RemoteSnapshotMetadata( - new DefaultArtifact( "a:b:1-SNAPSHOT" ), false); + new DefaultArtifact( "a:b:1-SNAPSHOT" ), false, new Date() ); metadata.merge( new Metadata() ); String dateAfter = gregorianDate(); diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml index 868d3447d4a9..80d361cb464e 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.6.3 + 3.9.0-SNAPSHOT maven-settings-builder @@ -62,7 +62,7 @@ under the License. maven-settings - org.sonatype.plexus + org.codehaus.plexus plexus-sec-dispatcher diff --git a/maven-settings/pom.xml b/maven-settings/pom.xml index 4a33dbe3eea4..cbdc405aa3e0 100644 --- a/maven-settings/pom.xml +++ b/maven-settings/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.6.3 + 3.9.0-SNAPSHOT maven-settings @@ -46,7 +46,7 @@ under the License. org.codehaus.modello modello-maven-plugin - 1.1.0 + 1.2.0 src/main/mdo/settings.mdo diff --git a/maven-settings/src/main/mdo/settings.mdo b/maven-settings/src/main/mdo/settings.mdo index 333d8bd7ac86..b0498df43a42 100644 --- a/maven-settings/src/main/mdo/settings.mdo +++ b/maven-settings/src/main/mdo/settings.mdo @@ -633,6 +633,15 @@ of the mirror to repositories with a matching layout (apart from a matching id). Since Maven 3. + + blocked + 1.2.0+ + boolean + false + + Whether this mirror should be blocked from any download request but fail the download process, explaining why. + + @@ -648,6 +657,10 @@ sb.append( ",mirrorOf=" ).append( mirrorOf ); sb.append( ",url=" ).append( this.url ); sb.append( ",name=" ).append( this.name ); + if ( isBlocked() ) + { + sb.append( ",blocked" ); + } sb.append( "]" ); return sb.toString(); } diff --git a/maven-settings/src/site/apt/index.apt b/maven-settings/src/site/apt/index.apt index 5d8e39c14a49..2b42ccd16a36 100644 --- a/maven-settings/src/site/apt/index.apt +++ b/maven-settings/src/site/apt/index.apt @@ -33,4 +33,4 @@ Maven Settings Model * A {{{./settings.html}Descriptor Reference}} - * An {{{https://maven.apache.org/xsd/settings-1.1.0.xsd}XSD}} + * An {{{https://maven.apache.org/xsd/settings-1.2.0.xsd}XSD}} diff --git a/maven-slf4j-provider/pom.xml b/maven-slf4j-provider/pom.xml index 604f8bbf7866..1ffc40f58b33 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.6.3 + 3.9.0-SNAPSHOT maven-slf4j-provider diff --git a/pom.xml b/pom.xml index c770f0d33c5c..84ec1b1d8b64 100644 --- a/pom.xml +++ b/pom.xml @@ -25,12 +25,12 @@ under the License. org.apache.maven maven-parent - 33 - ../pom/maven/pom.xml + 36 + maven - 3.6.3 + 3.9.0-SNAPSHOT pom Apache Maven @@ -47,26 +47,25 @@ under the License. 3.0.5 - 1.7 - 1.7 + 8 2.6.0 1.4 3.8.1 - 4.12 + 4.13.2 2.21.0 2.1.0 - 1.25 - 3.2.1 - 4.2.1 - 0.3.4 - 3.3.4 - 1.12.1 - 1.4 - 1.7 - 1.11 + 1.26 + 3.4.2 + 4.2.3 + 30.1-jre + 1.0.1 + 3.5.1 + 2.0 + 2.0 + 2.0.0 1.3 - 1.4.1 - 1.7.29 + 1.8.1 + 1.7.36 2.2.1 1.7.4 true @@ -77,7 +76,7 @@ under the License. ref/3-LATEST None **/package-info.java - 2019-11-07T12:32:18Z + 2022-03-05T11:41:15Z @@ -101,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.6.3 + maven-3.8.5 jira @@ -244,16 +243,66 @@ under the License. guice ${guiceVersion} no_aop + + + com.google.guava + guava + + + + + + com.google.guava + guava + ${guavaVersion} + + + com.google.code.findbugs + jsr305 + + + com.google.errorprone + error_prone_annotations + + + com.google.guava + failureaccess + + + com.google.guava + listenablefuture + + + com.google.j2objc + j2objc-annotations + + + org.checkerframework + checker-qual + + + + + + com.google.guava + failureaccess + ${guavafailureaccessVersion} org.eclipse.sisu org.eclipse.sisu.plexus - ${sisuInjectVersion} + ${sisuVersion} + + + javax.enterprise + cdi-api + + org.eclipse.sisu org.eclipse.sisu.inject - ${sisuInjectVersion} + ${sisuVersion} javax.inject @@ -262,8 +311,8 @@ under the License. javax.annotation - jsr250-api - 1.0 + javax.annotation-api + 1.3.2 org.codehaus.plexus @@ -289,12 +338,12 @@ under the License. org.apache.maven.shared maven-shared-utils - 3.2.1 + 3.3.4 org.fusesource.jansi jansi - 1.17.1 + 2.4.0 org.slf4j @@ -310,7 +359,7 @@ under the License. ch.qos.logback logback-classic - 1.2.1 + 1.2.11 true @@ -328,22 +377,7 @@ under the License. org.apache.maven.wagon wagon-http ${wagonVersion} - shaded - - - commons-logging - commons-logging - - - - - org.jsoup - jsoup - ${jsoupVersion} - org.apache.maven.resolver @@ -370,6 +404,16 @@ under the License. maven-resolver-connector-basic ${resolverVersion} + + org.apache.maven.resolver + maven-resolver-transport-file + ${resolverVersion} + + + org.apache.maven.resolver + maven-resolver-transport-http + ${resolverVersion} + org.apache.maven.resolver maven-resolver-transport-wagon @@ -402,12 +446,12 @@ under the License. ${commonsLangVersion} - org.sonatype.plexus + org.codehaus.plexus plexus-sec-dispatcher ${securityDispatcherVersion} - org.sonatype.plexus + org.codehaus.plexus plexus-cipher ${cipherVersion} @@ -464,22 +508,6 @@ under the License. - - - org.apache.maven.plugins - maven-source-plugin - 3.2.0 - - - org.apache.maven.plugins - maven-jar-plugin - 3.2.0 - - - org.apache.maven.plugins - maven-assembly-plugin - 3.2.0 - org.codehaus.plexus plexus-component-metadata @@ -493,19 +521,6 @@ under the License. - - org.eclipse.sisu - sisu-maven-plugin - ${sisuInjectVersion} - - - - main-index - test-index - - - - org.apache.maven.plugins maven-release-plugin @@ -561,10 +576,10 @@ under the License. src/test/remote-repo/** **/*.odg - src/main/appended-resources/licenses/CDDL-1.0.txt src/main/appended-resources/licenses/EPL-1.0.txt + src/main/appended-resources/licenses/unrecognized-javax.annotation-api-1.3.2.txt @@ -599,11 +614,11 @@ under the License. org.codehaus.mojo animal-sniffer-maven-plugin - 1.17 + 1.21 org.codehaus.mojo.signature - java17 + java18 1.0 @@ -642,6 +657,33 @@ under the License. + + org.apache.maven.plugins + maven-enforcer-plugin + + + + enforce + + validate + ensure-no-sonatype-cipher-and-sec-dispatcher + + + + + org.sonatype.plexus:plexus-sec-dispatcher + org.sonatype.plexus:plexus-cipher + + + ensure no more org.sonatype.plexus:plexus-cipher and org.sonatype.plexus:plexus-sec-dispatcher. + + + + true + + + +