From 39837b2acdd81a669a050ad64ed933bdcca94500 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sun, 22 Oct 2017 06:20:58 +0200 Subject: [PATCH 01/21] Set version to 3.4.0-SNAPSHOT. --- apache-maven/pom.xml | 2 +- maven-artifact/pom.xml | 2 +- maven-builder-support/pom.xml | 2 +- maven-compat/pom.xml | 2 +- maven-core/pom.xml | 2 +- maven-embedder/pom.xml | 2 +- maven-model-builder/pom.xml | 2 +- maven-model/pom.xml | 2 +- maven-plugin-api/pom.xml | 2 +- maven-repository-metadata/pom.xml | 2 +- maven-resolver-provider/pom.xml | 2 +- maven-settings-builder/pom.xml | 2 +- maven-settings/pom.xml | 2 +- maven-slf4j-provider/pom.xml | 4 ++-- pom.xml | 2 +- 15 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml index 166a14e97f4..d72b2f8f343 100644 --- a/apache-maven/pom.xml +++ b/apache-maven/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.5.4-SNAPSHOT + 3.4.0-SNAPSHOT apache-maven diff --git a/maven-artifact/pom.xml b/maven-artifact/pom.xml index ab842fad677..503e0977db8 100644 --- a/maven-artifact/pom.xml +++ b/maven-artifact/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-artifact diff --git a/maven-builder-support/pom.xml b/maven-builder-support/pom.xml index ab4fb0804bf..5cc3d8dea23 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.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-builder-support diff --git a/maven-compat/pom.xml b/maven-compat/pom.xml index eaa3abff85b..648ef8c3c59 100644 --- a/maven-compat/pom.xml +++ b/maven-compat/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-compat diff --git a/maven-core/pom.xml b/maven-core/pom.xml index 6fd47c5c3ad..03c6a237e05 100644 --- a/maven-core/pom.xml +++ b/maven-core/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-core diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml index 2994f04f5c0..80d8ddb05f6 100644 --- a/maven-embedder/pom.xml +++ b/maven-embedder/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-embedder diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml index a009b5cfb8c..dd60146275c 100644 --- a/maven-model-builder/pom.xml +++ b/maven-model-builder/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-model-builder diff --git a/maven-model/pom.xml b/maven-model/pom.xml index 952fab152ce..826c95f9c5d 100644 --- a/maven-model/pom.xml +++ b/maven-model/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-model diff --git a/maven-plugin-api/pom.xml b/maven-plugin-api/pom.xml index fcec291fc05..49346b6da63 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.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-plugin-api diff --git a/maven-repository-metadata/pom.xml b/maven-repository-metadata/pom.xml index b58c631e214..1bef9ef722d 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.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-repository-metadata diff --git a/maven-resolver-provider/pom.xml b/maven-resolver-provider/pom.xml index 20dda36eefd..29e7c3873f8 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.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-resolver-provider diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml index b18bcd948b1..886031cbbc8 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.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-settings-builder diff --git a/maven-settings/pom.xml b/maven-settings/pom.xml index c909107beac..39b17914f43 100644 --- a/maven-settings/pom.xml +++ b/maven-settings/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven maven - 3.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-settings diff --git a/maven-slf4j-provider/pom.xml b/maven-slf4j-provider/pom.xml index ee166a28104..3645ffcb04d 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.5.4-SNAPSHOT + 3.4.0-SNAPSHOT maven-slf4j-provider @@ -97,4 +97,4 @@ under the License. - \ No newline at end of file + diff --git a/pom.xml b/pom.xml index 660173b073e..b120242102a 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ under the License. maven - 3.5.4-SNAPSHOT + 3.4.0-SNAPSHOT pom Apache Maven From 4081b8c5ea03a4f6a4914ca060a238035f139d4c Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sun, 22 Oct 2017 06:21:23 +0200 Subject: [PATCH 02/21] Upgrade of Maven Resolver to 1.2.0-SNAPSHOT. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b120242102a..b38f1b6b59d 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ under the License. 1.7 1.9.1 1.3 - 1.1.1 + 1.2.0-SNAPSHOT 1.7.25 true From 40c5c414d994b7830141fbb18049b67d1c2ed72f Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Thu, 18 Dec 2014 02:37:09 +0100 Subject: [PATCH 03/21] [MNG-5738] Addition of command line flag '--legacy-reactor-resolution'. o Updated to add command line option '--legacy-reactor-resolution' to allow disabling workspace resolution introduced in Maven 3 as discussed at MPIR-238. --- .../java/org/apache/maven/DefaultMaven.java | 39 +++++++++++-------- .../DefaultMavenExecutionRequest.java | 14 +++++++ .../execution/MavenExecutionRequest.java | 11 ++++++ ...DefaultRepositorySystemSessionFactory.java | 8 +++- .../java/org/apache/maven/cli/CLIManager.java | 3 ++ .../java/org/apache/maven/cli/MavenCli.java | 11 ++++++ 6 files changed, 68 insertions(+), 18 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java index 7f052c139d7..548a39c2c18 100644 --- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java +++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java @@ -232,25 +232,30 @@ private MavenExecutionResult doExecute( MavenExecutionRequest request, MavenSess return addExceptionToResult( result, e ); } - WorkspaceReader reactorWorkspace; - try - { - reactorWorkspace = container.lookup( WorkspaceReader.class, ReactorReader.HINT ); - } - catch ( ComponentLookupException e ) + // As of Maven 3.4.0, workspace resolution can be disabled. See MNG-5738. + if ( !request.isUseLegacyReactorResolution() ) { - return addExceptionToResult( result, e ); - } + WorkspaceReader reactorWorkspace; + try + { + reactorWorkspace = container.lookup( WorkspaceReader.class, ReactorReader.HINT ); + } + 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() ) ); + // + // Desired order of precedence for local artifact repositories + // + // Reactor + // Workspace + // User Local Repository + // + repoSession.setWorkspaceReader( ChainedWorkspaceReader.newInstance( reactorWorkspace, + repoSession.getWorkspaceReader() ) ); + + } repoSession.setReadOnly(); diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java index fe558cd338d..291686a0b1d 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java +++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java @@ -163,6 +163,8 @@ public class DefaultMavenExecutionRequest private Map data; + private boolean useLegacyReactorResolution = false; + public DefaultMavenExecutionRequest() { } @@ -207,6 +209,7 @@ public static MavenExecutionRequest copy( MavenExecutionRequest original ) copy.setNoSnapshotUpdates( original.isNoSnapshotUpdates() ); copy.setExecutionListener( original.getExecutionListener() ); copy.setUseLegacyLocalRepository( original.isUseLegacyLocalRepository() ); + copy.setUseLegacyReactorResolution( original.isUseLegacyReactorResolution() ); copy.setBuilderId( original.getBuilderId() ); return copy; } @@ -1219,6 +1222,17 @@ public MavenExecutionRequest setUseLegacyLocalRepository( boolean useLegacyLocal } @Override + public boolean isUseLegacyReactorResolution() + { + return this.useLegacyReactorResolution; + } + + public MavenExecutionRequest setUseLegacyReactorResolution( boolean value ) + { + this.useLegacyReactorResolution = value; + return this; + } + public MavenExecutionRequest setBuilderId( String builderId ) { this.builderId = builderId; diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java index d006a434c54..3c8bda1786e 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java +++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java @@ -442,4 +442,15 @@ public interface MavenExecutionRequest * @since 3.3.0 */ Map getData(); + + /** + * @since 3.4.0 + */ + boolean isUseLegacyReactorResolution(); + + /** + * @since 3.4.0 + */ + MavenExecutionRequest setUseLegacyReactorResolution( boolean value ); + } 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 248a3b6dd12..69fa723ba93 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 @@ -93,6 +93,7 @@ public class DefaultRepositorySystemSessionFactory @Inject MavenRepositorySystem mavenRepositorySystem; + @SuppressWarnings( "checkstyle:methodlength" ) public DefaultRepositorySystemSession newRepositorySession( MavenExecutionRequest request ) { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); @@ -152,7 +153,12 @@ else if ( request.isUpdateSnapshots() ) session.setLocalRepositoryManager( repoSystem.newLocalRepositoryManager( session, localRepo ) ); } - if ( request.getWorkspaceReader() != null ) + // As of Maven 3.4.0, workspace resolution can be disabled. See MNG-5738. + if ( request.isUseLegacyReactorResolution() ) + { + session.setWorkspaceReader( null ); + } + else if ( request.getWorkspaceReader() != null ) { session.setWorkspaceReader( request.getWorkspaceReader() ); } 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 a9038bff26b..1261b098fa5 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 @@ -99,6 +99,8 @@ public class CLIManager public static final String LEGACY_LOCAL_REPOSITORY = "llr"; + public static final String LEGACY_REACTOR_RESOLUTION = "lrr"; + public static final String BUILDER = "b"; protected Options options; @@ -140,6 +142,7 @@ public CLIManager() options.addOption( OptionBuilder.withLongOpt( "threads" ).hasArg().withDescription( "Thread count, for instance 2.0C where C is core multiplied" ).create( THREADS ) ); options.addOption( OptionBuilder.withLongOpt( "legacy-local-repository" ).withDescription( "Use Maven 2 Legacy Local Repository behaviour, ie no use of _remote.repositories. Can also be activated by using -Dmaven.legacyLocalRepo=true" ).create( LEGACY_LOCAL_REPOSITORY ) ); options.addOption( OptionBuilder.withLongOpt( "builder" ).hasArg().withDescription( "The id of the build strategy to use" ).create( BUILDER ) ); + options.addOption( OptionBuilder.withLongOpt( "legacy-reactor-resolution" ).withDescription( "Use Maven 2 legacy reactor resolution behaviour, ie disable workspace resolution. Can also be activated by using -Dmaven.legacyReactorResolution=true" ).create( LEGACY_REACTOR_RESOLUTION ) ); // Adding this back in for compatibility with the verifier that hard codes this option. options.addOption( OptionBuilder.withLongOpt( "no-plugin-registry" ).withDescription( "Ineffective, only kept for backward compatibility" ).create( "npr" ) ); 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 c7e5d9ee354..c89b81bb4da 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 @@ -287,6 +287,7 @@ public int doMain( CliRequest cliRequest ) populateRequest( cliRequest ); encryption( cliRequest ); repository( cliRequest ); + resolution( cliRequest ); return execute( cliRequest ); } catch ( ExitException e ) @@ -946,6 +947,16 @@ private void repository( CliRequest cliRequest ) } } + private void resolution( CliRequest cliRequest ) + throws Exception + { + if ( cliRequest.commandLine.hasOption( CLIManager.LEGACY_REACTOR_RESOLUTION ) + || Boolean.getBoolean( "maven.legacyReactorResolution" ) ) + { + cliRequest.request.setUseLegacyReactorResolution( true ); + } + } + private int execute( CliRequest cliRequest ) throws MavenExecutionRequestPopulationException { From 842899dde04a626be99bb7863e37a9b0d3bfa107 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sun, 26 Mar 2017 00:18:24 +0100 Subject: [PATCH 04/21] [MNG-6112] Central repository in the 4.0.0 super POM should declare update policy 'never'. This reverts commit 8400984ac5201ae6bf06bfa88ade8a8468c76634. --- .../java/org/apache/maven/bridge/MavenRepositorySystem.java | 4 ++-- .../src/main/resources/org/apache/maven/model/pom-4.0.0.xml | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) 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 84ad93c9237..72f57a01fb9 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 @@ -574,8 +574,8 @@ public ArtifactRepository createDefaultRemoteRepository( MavenExecutionRequest r throws Exception { return createRepository( RepositorySystem.DEFAULT_REMOTE_REPO_URL, RepositorySystem.DEFAULT_REMOTE_REPO_ID, - true, ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY, false, - ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY, + true, ArtifactRepositoryPolicy.UPDATE_POLICY_NEVER, false, + ArtifactRepositoryPolicy.UPDATE_POLICY_NEVER, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN ); } diff --git a/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.0.0.xml b/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.0.0.xml index 8c26f71991e..aa3a295a01f 100644 --- a/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.0.0.xml +++ b/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.0.0.xml @@ -32,6 +32,9 @@ under the License. false + + never + From cb00b481d6ef5a0549311b6e0f5827b842ed0b03 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sat, 25 Mar 2017 23:01:03 +0100 Subject: [PATCH 05/21] [MNG-2893] Update the DefaultPluginManager to not use a project depMan for controlling it's transitive dependencies --- .../plugin/internal/DefaultPluginDependenciesResolver.java | 3 +++ 1 file changed, 3 insertions(+) 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 b79b15f264b..28dfb054a9f 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 @@ -54,6 +54,7 @@ import org.eclipse.aether.util.artifact.JavaScopes; import org.eclipse.aether.util.filter.AndDependencyFilter; import org.eclipse.aether.util.filter.ScopeDependencyFilter; +import org.eclipse.aether.util.graph.manager.ClassicDependencyManager; import org.eclipse.aether.util.graph.selector.AndDependencySelector; import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer; import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy; @@ -178,6 +179,7 @@ private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact, DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session ); pluginSession.setDependencySelector( selector ); pluginSession.setDependencyGraphTransformer( transformer ); + pluginSession.setDependencyManager( new ClassicDependencyManager() ); CollectRequest request = new CollectRequest(); request.setRequestContext( REPOSITORY_CONTEXT ); @@ -192,6 +194,7 @@ private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact, pluginDep = pluginDep.setScope( JavaScopes.RUNTIME ); } request.addDependency( pluginDep ); + request.addManagedDependency( pluginDep ); } DependencyRequest depRequest = new DependencyRequest( request, resolutionFilter ); From 76114a9f9b681cd5c6562317c911f72a64474021 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sun, 22 Oct 2017 06:22:10 +0200 Subject: [PATCH 06/21] [MNG-5359] Declared execution in PluginMgmt gets bound to lifecycle (regression) --- .../project/EmptyLifecyclePluginAnalyzer.java | 23 ++ .../lifecycle/DefaultLifecycleExecutor.java | 28 +-- .../lifecycle/LifeCyclePluginAnalyzer.java | 30 ++- .../maven/lifecycle/LifecycleExecutor.java | 26 +-- .../LifecycleMappingNotFoundException.java | 45 ++++ .../DefaultLifecyclePluginAnalyzer.java | 210 ++++++++++++++---- .../DefaultLifecycleBindingsInjector.java | 36 +-- .../EmptyLifecyclePluginAnalyzer.java | 23 ++ .../stub/LifeCyclePluginAnalyzerStub.java | 32 ++- 9 files changed, 350 insertions(+), 103 deletions(-) create mode 100644 maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleMappingNotFoundException.java diff --git a/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecyclePluginAnalyzer.java b/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecyclePluginAnalyzer.java index 672e07b35eb..16a0675b528 100644 --- a/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecyclePluginAnalyzer.java +++ b/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecyclePluginAnalyzer.java @@ -24,6 +24,8 @@ import java.util.Set; import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer; +import org.apache.maven.model.Build; +import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; import org.apache.maven.model.PluginExecution; @@ -33,6 +35,7 @@ public class EmptyLifecyclePluginAnalyzer implements LifeCyclePluginAnalyzer { + public Set getPluginsBoundByDefaultToAllLifecycles( String packaging ) { Set plugins; @@ -57,6 +60,26 @@ public Set getPluginsBoundByDefaultToAllLifecycles( String packaging ) return plugins; } + @Override + public Model getLifecycleModel( final Model model ) + { + if ( model == null ) + { + throw new NullPointerException( "model" ); + } + + final Model lifecycleModel = new Model(); + lifecycleModel.setBuild( new Build() ); + lifecycleModel.getBuild().setPluginManagement( model.getBuild() != null + ? model.getBuild().getPluginManagement() + : null ); + + lifecycleModel.getBuild().getPlugins(). + addAll( this.getPluginsBoundByDefaultToAllLifecycles( model.getPackaging() ) ); + + return lifecycleModel; + } + private Plugin newPlugin( String artifactId, String... goals ) { Plugin plugin = new Plugin(); diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java index dae18948ac5..d7174b22f6b 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java @@ -19,6 +19,11 @@ * under the License. */ +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.apache.maven.execution.MavenSession; import org.apache.maven.lifecycle.internal.LifecycleExecutionPlanCalculator; import org.apache.maven.lifecycle.internal.LifecycleStarter; @@ -42,11 +47,6 @@ import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; - /** * A facade that provides lifecycle services to components outside maven core. * @@ -88,19 +88,13 @@ public void execute( MavenSession session ) @Requirement private MojoDescriptorCreator mojoDescriptorCreator; - // These methods deal with construction intact Plugin object that look like they come from a standard - // block in a Maven POM. We have to do some wiggling to pull the sources of information - // together and this really shows the problem of constructing a sensible default configuration but - // it's all encapsulated here so it appears normalized to the POM builder. - - // We are going to take the project packaging and find all plugin in the default lifecycle and create - // fully populated Plugin objects, including executions with goals and default configuration taken - // from the plugin.xml inside a plugin. - // - // TODO This whole method could probably removed by injecting lifeCyclePluginAnalyzer straight into client site. - // TODO But for some reason the whole plexus appcontext refuses to start when I try this. - + /** + * @deprecated As of Maven 3.6.0, please use + * {@link LifeCyclePluginAnalyzer#getLifecycleModel(org.apache.maven.model.Model)}. + */ + @Deprecated public Set getPluginsBoundByDefaultToAllLifecycles( String packaging ) + throws LifecycleMappingNotFoundException { return lifeCyclePluginAnalyzer.getPluginsBoundByDefaultToAllLifecycles( packaging ); } diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java index ed07c1d5e74..d2b38951504 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java @@ -20,6 +20,8 @@ */ import java.util.Set; + +import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; /** @@ -28,5 +30,31 @@ */ public interface LifeCyclePluginAnalyzer { - Set getPluginsBoundByDefaultToAllLifecycles( String packaging ); + + /** + * @deprecated As of Maven 3.6.0, replaced by method {@link #getLifecycleModel(org.apache.maven.model.Model)}. + */ + @Deprecated + Set getPluginsBoundByDefaultToAllLifecycles( String packaging ) + throws LifecycleMappingNotFoundException; + + /** + * Gets the lifecycle {@code Model} for a given {@code Model}. + *

+ * The lifecycle model for a given model is the list of default build plugins plus lifecycle plugin execution + * management. + *

+ * + * @param model The {@code Model} to get the lifecycle {@code Model} for. + * + * @return The lifecycle {@code Model} for {@code model}. + * + * @throws NullPointerException if {@code model} is {@code null}. + * @throws LifecycleMappingNotFoundException if {@code model} declares an unsupported packaging. + * + * @since 3.6.0 + */ + Model getLifecycleModel( Model model ) + throws LifecycleMappingNotFoundException; + } diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java index 04c602cfe26..a3d639fc471 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java @@ -19,6 +19,9 @@ * under the License. */ +import java.util.List; +import java.util.Set; + import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.InvalidPluginDescriptorException; @@ -32,13 +35,10 @@ import org.apache.maven.plugin.version.PluginVersionResolutionException; import org.apache.maven.project.MavenProject; -import java.util.List; -import java.util.Set; - /** * A facade that provides lifecycle services to components outside Maven core. * - * @author Jason van Zyl + * @author Jason van Zyl */ public interface LifecycleExecutor { @@ -47,21 +47,13 @@ public interface LifecycleExecutor @Deprecated String ROLE = LifecycleExecutor.class.getName(); - // For a given project packaging find all the plugins that are bound to any registered - // lifecycles. The project builder needs to now what default plugin information needs to be - // merged into POM being built. Once the POM builder has this plugin information, versions can be assigned - // by the POM builder because they will have to be defined in plugin management. Once this is setComplete then it - // can be passed back so that the default configuration information can be populated. - // - // We need to know the specific version so that we can lookup the right version of the plugin descriptor - // which tells us what the default configuration is. - // - /** - * @return The plugins bound to the lifecycles of the specified packaging or {@code null} if the packaging is - * unknown. + * @deprecated As of Maven 3.6.0, please use + * {@link LifeCyclePluginAnalyzer#getLifecycleModel(org.apache.maven.model.Model)}. */ - Set getPluginsBoundByDefaultToAllLifecycles( String packaging ); + @Deprecated + Set getPluginsBoundByDefaultToAllLifecycles( String packaging ) + throws LifecycleMappingNotFoundException; MavenExecutionPlan calculateExecutionPlan( MavenSession session, String... tasks ) throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleMappingNotFoundException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleMappingNotFoundException.java new file mode 100644 index 00000000000..8bed7017263 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleMappingNotFoundException.java @@ -0,0 +1,45 @@ +package org.apache.maven.lifecycle; + +/* + * 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. + */ + +/** + * Signals a failure to locate a lifecycle mapping. + * + * @author Christian Schulte + * + * @since 3.6.0 + */ +public final class LifecycleMappingNotFoundException extends Exception +{ + + private String packaging; + + public LifecycleMappingNotFoundException( final String packaging ) + { + super( String.format( "No lifecycle mapping found for packaging '%s'.", packaging ) ); + this.packaging = packaging; + } + + public String getPackaging() + { + return this.packaging; + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer.java index 14653b7d251..b3eb4ce8a8a 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer.java @@ -19,32 +19,36 @@ * under the License. */ +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.apache.maven.lifecycle.DefaultLifecycles; import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer; import org.apache.maven.lifecycle.Lifecycle; +import org.apache.maven.lifecycle.LifecycleMappingNotFoundException; import org.apache.maven.lifecycle.mapping.LifecycleMapping; import org.apache.maven.lifecycle.mapping.LifecycleMojo; import org.apache.maven.lifecycle.mapping.LifecyclePhase; +import org.apache.maven.model.Build; +import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; import org.apache.maven.model.PluginExecution; +import org.apache.maven.model.PluginManagement; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.Xpp3Dom; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - /** * NOTE: This class is not part of any public api and can be changed or deleted without prior notice. - * + * * @since 3.0 * @author Benjamin Bentmann * @author Jason van Zyl @@ -69,64 +73,117 @@ public DefaultLifecyclePluginAnalyzer() { } + // ----------------------------------------------------------------------------------------------------------------- + // Comment regarding these methods moved here from LifecycleExecuter: + // ----------------------------------------------------------------------------------------------------------------- + // For a given project packaging find all the plugins that are bound to any registered + // lifecycles. The project builder needs to now what default plugin information needs to be + // merged into POM being built. Once the POM builder has this plugin information, versions can be assigned + // by the POM builder because they will have to be defined in plugin management. Once this is setComplete then it + // can be passed back so that the default configuration information can be populated. + // + // We need to know the specific version so that we can lookup the right version of the plugin descriptor + // which tells us what the default configuration is. + // ----------------------------------------------------------------------------------------------------------------- + // Comment regarding these methods moved here from DefaultLifecycleExecutor: + // ----------------------------------------------------------------------------------------------------------------- // These methods deal with construction intact Plugin object that look like they come from a standard // block in a Maven POM. We have to do some wiggling to pull the sources of information // together and this really shows the problem of constructing a sensible default configuration but // it's all encapsulated here so it appears normalized to the POM builder. - // We are going to take the project packaging and find all plugins in the default lifecycle and create // fully populated Plugin objects, including executions with goals and default configuration taken // from the plugin.xml inside a plugin. - // - + @Override + @Deprecated public Set getPluginsBoundByDefaultToAllLifecycles( String packaging ) + throws LifecycleMappingNotFoundException + { + if ( packaging == null ) + { + throw new NullPointerException( "packaging" ); + } + + final Model model = new Model(); + model.setPackaging( packaging ); + + final Set plugins = new HashSet<>( this.getLifecycleModel( model ).getBuild().getPlugins() ); + return Collections.unmodifiableSet( plugins ); + } + + @Override + public Model getLifecycleModel( final Model model ) + throws LifecycleMappingNotFoundException { + if ( model == null ) + { + throw new NullPointerException( "model" ); + } + + final PluginManagement pluginManagement = + model.getBuild() != null && model.getBuild().getPluginManagement() != null + ? model.getBuild().getPluginManagement().clone() + : null; + + final Model lifecycleModel = new Model(); + lifecycleModel.setBuild( new Build() ); + lifecycleModel.getBuild().setPluginManagement( pluginManagement != null + ? pluginManagement.clone() + : new PluginManagement() ); + + for ( final Plugin managedPlugin : lifecycleModel.getBuild().getPluginManagement().getPlugins() ) + { + managedPlugin.getExecutions().clear(); + } + if ( logger.isDebugEnabled() ) { - logger.debug( "Looking up lifecycle mappings for packaging " + packaging + " from " - + Thread.currentThread().getContextClassLoader() ); + logger.debug( "Looking up lifecycle mappings for packaging " + model.getPackaging() + " from " + + Thread.currentThread().getContextClassLoader() ); + } - LifecycleMapping lifecycleMappingForPackaging = lifecycleMappings.get( packaging ); + final LifecycleMapping lifecycleMappingForPackaging = this.lifecycleMappings.get( model.getPackaging() ); if ( lifecycleMappingForPackaging == null ) { - return null; + throw new LifecycleMappingNotFoundException( model.getPackaging() ); } - Map plugins = new LinkedHashMap<>(); + final Map plugins = new LinkedHashMap<>(); for ( Lifecycle lifecycle : getOrderedLifecycles() ) { - org.apache.maven.lifecycle.mapping.Lifecycle lifecycleConfiguration = + final org.apache.maven.lifecycle.mapping.Lifecycle lifecycleConfiguration = lifecycleMappingForPackaging.getLifecycles().get( lifecycle.getId() ); - Map phaseToGoalMapping = null; - - if ( lifecycleConfiguration != null ) - { - phaseToGoalMapping = lifecycleConfiguration.getLifecyclePhases(); - } - else if ( lifecycle.getDefaultLifecyclePhases() != null ) - { - phaseToGoalMapping = lifecycle.getDefaultLifecyclePhases(); - } + final Map phaseToGoalMapping = + lifecycleConfiguration != null + ? lifecycleConfiguration.getLifecyclePhases() + : lifecycle.getDefaultLifecyclePhases() != null + ? lifecycle.getDefaultLifecyclePhases() + : null; if ( phaseToGoalMapping != null ) { - for ( Map.Entry goalsForLifecyclePhase : phaseToGoalMapping.entrySet() ) + for ( final Map.Entry goalsForLifecyclePhase : phaseToGoalMapping.entrySet() ) { - String phase = goalsForLifecyclePhase.getKey(); - LifecyclePhase goals = goalsForLifecyclePhase.getValue(); + final String phase = goalsForLifecyclePhase.getKey(); + final LifecyclePhase goals = goalsForLifecyclePhase.getValue(); + if ( goals != null ) { - parseLifecyclePhaseDefinitions( plugins, phase, goals ); + parseLifecyclePhaseDefinitions( plugins, phase, goals, lifecycle, lifecycleModel, + pluginManagement ); + } } } } - return plugins.keySet(); + lifecycleModel.getBuild().getPlugins().addAll( plugins.keySet() ); + + return lifecycleModel; } private List getOrderedLifecycles() @@ -136,42 +193,45 @@ private List getOrderedLifecycles() List lifecycles = new ArrayList<>( defaultLifeCycles.getLifeCycles() ); Collections.sort( lifecycles, new Comparator() - { + { - public int compare( Lifecycle l1, Lifecycle l2 ) - { - return l1.getId().compareTo( l2.getId() ); - } + @Override + public int compare( Lifecycle l1, Lifecycle l2 ) + { + return l1.getId().compareTo( l2.getId() ); + } - } ); + } ); return lifecycles; } - private void parseLifecyclePhaseDefinitions( Map plugins, String phase, LifecyclePhase goals ) + private void parseLifecyclePhaseDefinitions( Map plugins, String phase, LifecyclePhase goals, + final Lifecycle lifecycle, final Model lifecycleModel, + final PluginManagement pluginManagement ) { List mojos = goals.getMojos(); + if ( mojos != null ) { - for ( int i = 0; i < mojos.size(); i++ ) { LifecycleMojo mojo = mojos.get( i ); - + GoalSpec gs = parseGoalSpec( mojo.getGoal() ); - + if ( gs == null ) { logger.warn( "Ignored invalid goal specification '" + mojo.getGoal() - + "' from lifecycle mapping for phase " + phase ); + + "' from lifecycle mapping for phase '" + phase + "'" ); continue; } - + Plugin plugin = new Plugin(); plugin.setGroupId( gs.groupId ); plugin.setArtifactId( gs.artifactId ); plugin.setVersion( gs.version ); - + Plugin existing = plugins.get( plugin ); if ( existing != null ) { @@ -185,7 +245,7 @@ private void parseLifecyclePhaseDefinitions( Map plugins, String { plugins.put( plugin, plugin ); } - + PluginExecution execution = new PluginExecution(); execution.setId( getExecutionId( plugin, gs.goal ) ); execution.setPhase( phase ); @@ -200,6 +260,38 @@ private void parseLifecyclePhaseDefinitions( Map plugins, String plugin.setDependencies( mojo.getDependencies() ); plugin.getExecutions().add( execution ); + + if ( pluginManagement != null ) + { + final Plugin managedPlugin = this.getManagedPlugin( pluginManagement, plugin ); + + if ( managedPlugin != null ) + { + final List defaultExecutions = + new ArrayList<>( managedPlugin.getExecutions().size() ); + + for ( final PluginExecution pluginExecution : managedPlugin.getExecutions() ) + { + // What if the plugin's default phase (== null) is not from the lifecyle? + if ( pluginExecution.getPhase() == null + || lifecycle.getPhases().contains( pluginExecution.getPhase() ) ) + { + defaultExecutions.add( pluginExecution ); + } + } + + final Plugin defaultManagedPlugin = + this.getManagedPlugin( lifecycleModel.getBuild().getPluginManagement(), + managedPlugin ); + + for ( final PluginExecution pluginExecution : defaultExecutions ) + { + defaultManagedPlugin.addExecution( pluginExecution ); + } + + managedPlugin.getExecutions().removeAll( defaultExecutions ); + } + } } } } @@ -253,6 +345,28 @@ private String getExecutionId( Plugin plugin, String goal ) return id; } + private Plugin getManagedPlugin( final PluginManagement pluginManagement, final Plugin plugin ) + { + Plugin managedPlugin = null; + final String key = plugin.getKey(); + + if ( pluginManagement != null ) + { + for ( int i = 0, s0 = pluginManagement.getPlugins().size(); i < s0; i++ ) + { + final Plugin current = pluginManagement.getPlugins().get( i ); + + if ( current.getKey().equals( key ) ) + { + managedPlugin = current; + break; + } + } + } + + return managedPlugin; + } + static class GoalSpec { diff --git a/maven-core/src/main/java/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.java b/maven-core/src/main/java/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.java index 90cf8da7e5a..0b2ce9013d6 100644 --- a/maven-core/src/main/java/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.java +++ b/maven-core/src/main/java/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.java @@ -20,13 +20,13 @@ */ import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer; +import org.apache.maven.lifecycle.LifecycleMappingNotFoundException; import org.apache.maven.model.Build; import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; @@ -34,9 +34,9 @@ import org.apache.maven.model.PluginExecution; import org.apache.maven.model.PluginManagement; import org.apache.maven.model.building.ModelBuildingRequest; -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.merge.MavenModelMerger; import org.codehaus.plexus.component.annotations.Component; @@ -55,27 +55,33 @@ public class DefaultLifecycleBindingsInjector private LifecycleBindingsMerger merger = new LifecycleBindingsMerger(); @Requirement - private LifeCyclePluginAnalyzer lifecycle; + private LifeCyclePluginAnalyzer lifecyclePluginAnalyzer; + @Override public void injectLifecycleBindings( Model model, ModelBuildingRequest request, ModelProblemCollector problems ) { - String packaging = model.getPackaging(); + try + { + final Model lifecycleModel = this.lifecyclePluginAnalyzer.getLifecycleModel( model ); - Collection defaultPlugins = lifecycle.getPluginsBoundByDefaultToAllLifecycles( packaging ); + if ( model.getBuild() == null ) + { + model.setBuild( new Build() ); + } - if ( defaultPlugins == null ) - { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "Unknown packaging: " + packaging ) - .setLocation( model.getLocation( "packaging" ) ) ); + final PluginManagement pluginManagement = model.getBuild().getPluginManagement(); + + model.getBuild().setPluginManagement( lifecycleModel.getBuild().getPluginManagement() ); + + merger.merge( model, lifecycleModel ); + + model.getBuild().setPluginManagement( pluginManagement ); } - else if ( !defaultPlugins.isEmpty() ) + catch ( final LifecycleMappingNotFoundException e ) { - Model lifecycleModel = new Model(); - lifecycleModel.setBuild( new Build() ); - lifecycleModel.getBuild().getPlugins().addAll( defaultPlugins ); + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ). + setException( e ).setLocation( model.getLocation( "packaging" ) ) ); - merger.merge( model, lifecycleModel ); } } diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/EmptyLifecyclePluginAnalyzer.java b/maven-core/src/test/java/org/apache/maven/lifecycle/EmptyLifecyclePluginAnalyzer.java index a812c269009..b48a909e422 100644 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/EmptyLifecyclePluginAnalyzer.java +++ b/maven-core/src/test/java/org/apache/maven/lifecycle/EmptyLifecyclePluginAnalyzer.java @@ -23,6 +23,8 @@ import java.util.LinkedHashSet; import java.util.Set; +import org.apache.maven.model.Build; +import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; import org.apache.maven.model.PluginExecution; @@ -32,6 +34,7 @@ public class EmptyLifecyclePluginAnalyzer implements LifeCyclePluginAnalyzer { + public Set getPluginsBoundByDefaultToAllLifecycles( String packaging ) { Set plugins; @@ -56,6 +59,26 @@ public Set getPluginsBoundByDefaultToAllLifecycles( String packaging ) return plugins; } + @Override + public Model getLifecycleModel( final Model model ) + { + if ( model == null ) + { + throw new NullPointerException( "model" ); + } + + final Model lifecycleModel = new Model(); + lifecycleModel.setBuild( new Build() ); + lifecycleModel.getBuild().setPluginManagement( model.getBuild() != null + ? model.getBuild().getPluginManagement() + : null ); + + lifecycleModel.getBuild().getPlugins(). + addAll( this.getPluginsBoundByDefaultToAllLifecycles( model.getPackaging() ) ); + + return lifecycleModel; + } + private Plugin newPlugin( String artifactId, String... goals ) { Plugin plugin = new Plugin(); diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java index b067e244a9a..7bd23e62794 100644 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java +++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java @@ -12,23 +12,25 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ - package org.apache.maven.lifecycle.internal.stub; -import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer; -import org.apache.maven.model.Plugin; -import org.apache.maven.model.PluginExecution; - import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer; +import org.apache.maven.model.Build; +import org.apache.maven.model.Model; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.PluginExecution; + /** * @author Kristian Rosenvold */ public class LifeCyclePluginAnalyzerStub implements LifeCyclePluginAnalyzer { + public Set getPluginsBoundByDefaultToAllLifecycles( String packaging ) { Set plugins; @@ -53,6 +55,26 @@ public Set getPluginsBoundByDefaultToAllLifecycles( String packaging ) return plugins; } + @Override + public Model getLifecycleModel( final Model model ) + { + if ( model == null ) + { + throw new NullPointerException( "model" ); + } + + final Model lifecycleModel = new Model(); + lifecycleModel.setBuild( new Build() ); + lifecycleModel.getBuild().setPluginManagement( model.getBuild() != null + ? model.getBuild().getPluginManagement() + : null ); + + lifecycleModel.getBuild().getPlugins(). + addAll( this.getPluginsBoundByDefaultToAllLifecycles( model.getPackaging() ) ); + + return lifecycleModel; + } + private Plugin newPlugin( String artifactId, String... goals ) { Plugin plugin = new Plugin(); From a20d68def4565ee50b90d0cd058deaa05df174f5 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Thu, 25 Feb 2016 19:46:13 +0100 Subject: [PATCH 07/21] [MNG-5984] Maven core extension resolution ignores repositories from activeByDefault profiles in settings.xml --- .../apache/maven/settings/SettingsUtils.java | 2 +- .../java/org/apache/maven/cli/MavenCli.java | 160 +++++++++++++++--- .../SettingsXmlConfigurationProcessor.java | 65 ++----- 3 files changed, 153 insertions(+), 74 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java b/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java index 8da696e8acc..16ccdb65f09 100644 --- a/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java +++ b/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java @@ -139,7 +139,7 @@ public static org.apache.maven.model.Profile convertFromSettingsProfile( Profile profile.setId( settingsProfile.getId() ); - profile.setSource( "settings.xml" ); + profile.setSource( org.apache.maven.model.Profile.SOURCE_SETTINGS ); Activation settingsActivation = settingsProfile.getActivation(); 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 c89b81bb4da..ac8081e71d4 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 @@ -19,6 +19,29 @@ * under the License. */ +import java.io.BufferedInputStream; +import java.io.Console; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import com.google.inject.AbstractModule; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; @@ -27,6 +50,8 @@ import org.apache.maven.BuildAbort; import org.apache.maven.InternalErrorException; import org.apache.maven.Maven; +import org.apache.maven.artifact.InvalidRepositoryException; +import org.apache.maven.bridge.MavenRepositorySystem; import org.apache.maven.building.FileSource; import org.apache.maven.building.Problem; import org.apache.maven.building.Source; @@ -58,7 +83,15 @@ import org.apache.maven.extension.internal.CoreExports; import org.apache.maven.extension.internal.CoreExtensionEntry; import org.apache.maven.lifecycle.LifecycleExecutionException; +import org.apache.maven.model.Profile; +import org.apache.maven.model.Repository; +import org.apache.maven.model.building.DefaultModelProblem; +import org.apache.maven.model.building.ModelProblem; +import org.apache.maven.model.building.ModelProblemCollector; +import org.apache.maven.model.building.ModelProblemCollectorRequest; import org.apache.maven.model.building.ModelProcessor; +import org.apache.maven.model.profile.DefaultProfileActivationContext; +import org.apache.maven.model.profile.ProfileSelector; import org.apache.maven.project.MavenProject; import org.apache.maven.properties.internal.EnvironmentUtils; import org.apache.maven.properties.internal.SystemProperties; @@ -90,29 +123,6 @@ import org.sonatype.plexus.components.sec.dispatcher.SecUtil; import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity; -import java.io.BufferedInputStream; -import java.io.Console; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import static org.apache.maven.shared.utils.logging.MessageUtils.buffer; // TODO push all common bits back to plexus cli and prepare for transition to Guice. We don't need 50 ways to make CLIs @@ -167,6 +177,8 @@ public class MavenCli private Map configurationProcessors; + private ProfileSelector profileSelector; + public MavenCli() { this( null ); @@ -288,6 +300,7 @@ public int doMain( CliRequest cliRequest ) encryption( cliRequest ); repository( cliRequest ); resolution( cliRequest ); + profiles( cliRequest ); return execute( cliRequest ); } catch ( ExitException e ) @@ -687,6 +700,8 @@ protected void configure() dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" ); + profileSelector = container.lookup( ProfileSelector.class ); + return container; } @@ -751,6 +766,10 @@ protected void configure() request = executionRequestPopulator.populateDefaults( request ); + profileSelector = container.lookup( ProfileSelector.class ); + + profiles( request ); + BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class ); return resolver.loadCoreExtensions( request, providedArtifacts, extensions ); @@ -940,8 +959,8 @@ else if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_PASSWORD ) ) private void repository( CliRequest cliRequest ) throws Exception { - if ( cliRequest.commandLine.hasOption( CLIManager.LEGACY_LOCAL_REPOSITORY ) || Boolean.getBoolean( - "maven.legacyLocalRepo" ) ) + if ( cliRequest.commandLine.hasOption( CLIManager.LEGACY_LOCAL_REPOSITORY ) + || Boolean.getBoolean( "maven.legacyLocalRepo" ) ) { cliRequest.request.setUseLegacyLocalRepository( true ); } @@ -957,6 +976,97 @@ private void resolution( CliRequest cliRequest ) } } + private void profiles( final CliRequest request ) + { + this.profiles( request.getRequest() ); + } + + private void profiles( final MavenExecutionRequest request ) + { + // Adds repositories from profiles. + final DefaultProfileActivationContext profileActivationContext = new DefaultProfileActivationContext(); + profileActivationContext.setActiveProfileIds( request.getActiveProfiles() ); + profileActivationContext.setInactiveProfileIds( request.getInactiveProfiles() ); + profileActivationContext.setSystemProperties( request.getSystemProperties() ); + profileActivationContext.setUserProperties( request.getUserProperties() ); + profileActivationContext.setProjectDirectory( request.getPom() != null + ? request.getPom().getParentFile() + : null ); + + final List modelProblems = new ArrayList<>(); + final List activeProfiles = + this.profileSelector.getActiveProfiles( request.getProfiles(), profileActivationContext, + new ModelProblemCollector() + { + + @Override + public void add( final ModelProblemCollectorRequest req ) + { + modelProblems.add( new DefaultModelProblem( + req.getMessage(), req.getSeverity(), + req.getVersion(), Profile.SOURCE_SETTINGS, -1, -1, + null, req.getException() ) ); + + } + + } ); + + if ( !modelProblems.isEmpty() ) + { + slf4jLogger.warn( "" ); + slf4jLogger.warn( "Some problems were encountered while processing profiles" ); + + for ( final ModelProblem problem : modelProblems ) + { + slf4jLogger.warn( problem.getMessage(), problem.getException() ); + } + + slf4jLogger.warn( "" ); + } + + if ( !activeProfiles.isEmpty() ) + { + for ( final Profile profile : activeProfiles ) + { + final List remoteRepositories = profile.getRepositories(); + + for ( final Repository remoteRepository : remoteRepositories ) + { + try + { + request.addRemoteRepository( + MavenRepositorySystem.buildArtifactRepository( remoteRepository ) ); + + } + catch ( final InvalidRepositoryException e ) + { + slf4jLogger.warn( String.format( "Failure adding repository '%s' from profile '%s'.", + remoteRepository.getId(), profile.getId() ), e ); + + } + } + + final List pluginRepositories = profile.getPluginRepositories(); + + for ( final Repository pluginRepository : pluginRepositories ) + { + try + { + request.addPluginArtifactRepository( + MavenRepositorySystem.buildArtifactRepository( pluginRepository ) ); + + } + catch ( InvalidRepositoryException e ) + { + slf4jLogger.warn( String.format( "Failure adding plugin repository '%s' from profile '%s'.", + pluginRepository.getId(), profile.getId() ), e ); + + } + } + } + } + } + private int execute( CliRequest cliRequest ) throws MavenExecutionRequestPopulationException { diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor.java b/maven-embedder/src/main/java/org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor.java index 2536a22ced7..9b21a3be60f 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor.java @@ -21,11 +21,8 @@ import java.io.File; import java.io.FileNotFoundException; -import java.util.List; import org.apache.commons.cli.CommandLine; -import org.apache.maven.artifact.InvalidRepositoryException; -import org.apache.maven.bridge.MavenRepositorySystem; import org.apache.maven.building.Source; import org.apache.maven.cli.CLIManager; import org.apache.maven.cli.CliRequest; @@ -33,7 +30,6 @@ import org.apache.maven.execution.MavenExecutionRequestPopulationException; import org.apache.maven.settings.Mirror; import org.apache.maven.settings.Proxy; -import org.apache.maven.settings.Repository; import org.apache.maven.settings.Server; import org.apache.maven.settings.Settings; import org.apache.maven.settings.SettingsUtils; @@ -42,7 +38,6 @@ import org.apache.maven.settings.building.SettingsBuildingRequest; import org.apache.maven.settings.building.SettingsBuildingResult; import org.apache.maven.settings.building.SettingsProblem; -import org.apache.maven.settings.crypto.SettingsDecrypter; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.slf4j.Logger; @@ -54,6 +49,7 @@ public class SettingsXmlConfigurationProcessor implements ConfigurationProcessor { + public static final String HINT = "settings"; public static final String USER_HOME = System.getProperty( "user.home" ); @@ -71,9 +67,6 @@ public class SettingsXmlConfigurationProcessor @Requirement private SettingsBuilder settingsBuilder; - @Requirement - private SettingsDecrypter settingsDecrypter; - @Override public void process( CliRequest cliRequest ) throws Exception @@ -91,8 +84,9 @@ public void process( CliRequest cliRequest ) if ( !userSettingsFile.isFile() ) { - throw new FileNotFoundException( "The specified user settings file does not exist: " - + userSettingsFile ); + throw new FileNotFoundException( String.format( "The specified user settings file does not exist: %s", + userSettingsFile ) ); + } } else @@ -109,8 +103,9 @@ public void process( CliRequest cliRequest ) if ( !globalSettingsFile.isFile() ) { - throw new FileNotFoundException( "The specified global settings file does not exist: " - + globalSettingsFile ); + throw new FileNotFoundException( String.format( "The specified global settings file does not exist: %s", + globalSettingsFile ) ); + } } else @@ -132,10 +127,13 @@ public void process( CliRequest cliRequest ) request.getEventSpyDispatcher().onEvent( settingsRequest ); } - logger.debug( "Reading global settings from " - + getLocation( settingsRequest.getGlobalSettingsSource(), settingsRequest.getGlobalSettingsFile() ) ); - logger.debug( "Reading user settings from " - + getLocation( settingsRequest.getUserSettingsSource(), settingsRequest.getUserSettingsFile() ) ); + logger.debug( String.format( "Reading global settings from %s", + getLocation( settingsRequest.getGlobalSettingsSource(), + settingsRequest.getGlobalSettingsFile() ) ) ); + + logger.debug( String.format( "Reading user settings from %s", + getLocation( settingsRequest.getUserSettingsSource(), + settingsRequest.getUserSettingsFile() ) ) ); SettingsBuildingResult settingsResult = settingsBuilder.build( settingsRequest ); @@ -221,43 +219,13 @@ private MavenExecutionRequest populateFromSettings( MavenExecutionRequest reques request.addMirror( mirror ); } - request.setActiveProfiles( settings.getActiveProfiles() ); + request.addActiveProfiles( settings.getActiveProfiles() ); for ( org.apache.maven.settings.Profile rawProfile : settings.getProfiles() ) { request.addProfile( SettingsUtils.convertFromSettingsProfile( rawProfile ) ); - - if ( settings.getActiveProfiles().contains( rawProfile.getId() ) ) - { - List remoteRepositories = rawProfile.getRepositories(); - for ( Repository remoteRepository : remoteRepositories ) - { - try - { - request.addRemoteRepository( - MavenRepositorySystem.buildArtifactRepository( remoteRepository ) ); - } - catch ( InvalidRepositoryException e ) - { - // do nothing for now - } - } - - List pluginRepositories = rawProfile.getPluginRepositories(); - for ( Repository pluginRepository : pluginRepositories ) - { - try - { - request.addPluginArtifactRepository( - MavenRepositorySystem.buildArtifactRepository( pluginRepository ) ); - } - catch ( InvalidRepositoryException e ) - { - // do nothing for now - } - } - } } + return request; } @@ -290,4 +258,5 @@ else if ( file.getPath().startsWith( File.separator ) ) return new File( workingDirectory, file.getPath() ).getAbsoluteFile(); } } + } From be40caa76fdc9acf5fd421c2805c37544fcac345 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sat, 12 Nov 2016 21:06:19 +0100 Subject: [PATCH 08/21] [MNG-6114] Profiles from the global settings should be ordered before profiles from the user settings. --- .../org/apache/maven/settings/merge/MavenSettingsMerger.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/merge/MavenSettingsMerger.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/merge/MavenSettingsMerger.java index 8d9f67b1fcb..cb5f6c166f1 100644 --- a/maven-settings-builder/src/main/java/org/apache/maven/settings/merge/MavenSettingsMerger.java +++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/merge/MavenSettingsMerger.java @@ -111,6 +111,7 @@ private static void shallowMergeById( List domin String recessiveSourceLevel ) { Map dominantById = mapById( dominant ); + final List identifiables = new ArrayList<>( recessive.size() ); for ( T identifiable : recessive ) { @@ -118,9 +119,11 @@ private static void shallowMergeById( List domin { identifiable.setSourceLevel( recessiveSourceLevel ); - dominant.add( identifiable ); + identifiables.add( identifiable ); } } + + dominant.addAll( 0, identifiables ); } /** From 2775179b5abf1a6eb292ef7f360984ac5f08864d Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Mon, 14 Dec 2015 04:57:47 +0100 Subject: [PATCH 09/21] [MNG-6164] Collections inconsistently immutable. --- .../maven/artifact/DefaultArtifact.java | 2 +- .../artifact/versioning/VersionRange.java | 2 +- .../repository/DefaultArtifactRepository.java | 2 +- .../repository/MetadataResolutionResult.java | 27 +++++++++++++------ .../repository/MavenArtifactRepository.java | 2 +- .../resolver/ArtifactResolutionResult.java | 27 +++++++++++++------ .../artifact/resolver/ResolutionNode.java | 1 + .../maven/exception/ExceptionSummary.java | 5 +++- .../DefaultMavenExecutionResult.java | 6 +++-- .../lifecycle/internal/MojoExecutor.java | 18 +++++++------ .../internal/DefaultMavenPluginManager.java | 2 +- .../prefix/DefaultPluginPrefixRequest.java | 4 +-- .../version/DefaultPluginVersionRequest.java | 2 +- .../DefaultDependencyResolutionResult.java | 5 +++- .../maven/project/DefaultProjectBuilder.java | 1 + .../project/DefaultProjectRealmCache.java | 4 ++- .../apache/maven/project/MavenProject.java | 19 +++++++------ .../project/artifact/ProjectArtifact.java | 7 +++-- .../java/org/apache/maven/cli/MavenCli.java | 4 ++- .../building/ModelBuildingException.java | 2 +- 20 files changed, 91 insertions(+), 51 deletions(-) diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java index 1167e91a538..3fa1907c31d 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java @@ -273,7 +273,7 @@ public Collection getMetadataList() return Collections.emptyList(); } - return metadataMap.values(); + return Collections.unmodifiableCollection( metadataMap.values() ); } // ---------------------------------------------------------------------- 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 56343b2f6df..e9196213fb9 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 @@ -262,7 +262,7 @@ public VersionRange restrict( VersionRange restriction ) } else { - restrictions = intersection( r1, r2 ); + restrictions = Collections.unmodifiableList( intersection( r1, r2 ) ); } ArtifactVersion version = null; 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 f5db5ef6349..16b82c50700 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 @@ -256,7 +256,7 @@ public void setMirroredRepositories( List mirroredRepositori { if ( mirroredRepositories != null ) { - this.mirroredRepositories = mirroredRepositories; + this.mirroredRepositories = Collections.unmodifiableList( mirroredRepositories ); } else { diff --git a/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionResult.java b/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionResult.java index 70b9c3fdc56..7be1d96950a 100644 --- a/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionResult.java +++ b/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionResult.java @@ -118,7 +118,10 @@ public boolean hasMissingArtifacts() public List getMissingArtifacts() { - return missingArtifacts == null ? Collections.emptyList() : missingArtifacts; + return missingArtifacts == null + ? Collections.emptyList() + : Collections.unmodifiableList( missingArtifacts ); + } public MetadataResolutionResult addMissingArtifact( Artifact artifact ) @@ -148,7 +151,10 @@ public boolean hasExceptions() public List getExceptions() { - return exceptions == null ? Collections.emptyList() : exceptions; + return exceptions == null + ? Collections.emptyList() + : Collections.unmodifiableList( exceptions ); + } // ------------------------------------------------------------------------ @@ -185,7 +191,10 @@ public OverConstrainedVersionException getVersionRangeViolation( int i ) public List getVersionRangeViolations() { - return versionRangeViolations == null ? Collections.emptyList() : versionRangeViolations; + return versionRangeViolations == null + ? Collections.emptyList() + : Collections.unmodifiableList( versionRangeViolations ); + } // ------------------------------------------------------------------------ @@ -217,8 +226,10 @@ public ArtifactResolutionException getMetadataResolutionException( int i ) public List getMetadataResolutionExceptions() { - return metadataResolutionExceptions == null ? Collections.emptyList() - : metadataResolutionExceptions; + return metadataResolutionExceptions == null + ? Collections.emptyList() + : Collections.unmodifiableList( metadataResolutionExceptions ); + } // ------------------------------------------------------------------------ @@ -246,7 +257,7 @@ public List getErrorArtifactExceptions() return Collections.emptyList(); } - return errorArtifactExceptions; + return Collections.unmodifiableList( errorArtifactExceptions ); } // ------------------------------------------------------------------------ @@ -283,7 +294,7 @@ public List getCircularDependencyExceptions() return Collections.emptyList(); } - return circularDependencyExceptions; + return Collections.unmodifiableList( circularDependencyExceptions ); } // ------------------------------------------------------------------------ @@ -297,7 +308,7 @@ public List getRepositories() return Collections.emptyList(); } - return repositories; + return Collections.unmodifiableList( repositories ); } public MetadataResolutionResult setRepositories( final List repositories ) 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 d4c64f0bf70..f04007ee6e3 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 @@ -405,7 +405,7 @@ public void setMirroredRepositories( List mirroredRepositori { if ( mirroredRepositories != null ) { - this.mirroredRepositories = mirroredRepositories; + this.mirroredRepositories = Collections.unmodifiableList( mirroredRepositories ); } else { diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionResult.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionResult.java index 6de04f3cbda..ffae1d35601 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionResult.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionResult.java @@ -130,7 +130,10 @@ public boolean hasMissingArtifacts() public List getMissingArtifacts() { - return missingArtifacts == null ? Collections.emptyList() : missingArtifacts; + return missingArtifacts == null + ? Collections.emptyList() + : Collections.unmodifiableList( missingArtifacts ); + } public ArtifactResolutionResult addMissingArtifact( Artifact artifact ) @@ -165,7 +168,10 @@ public boolean hasExceptions() public List getExceptions() { - return exceptions == null ? Collections.emptyList() : exceptions; + return exceptions == null + ? Collections.emptyList() + : Collections.unmodifiableList( exceptions ); + } // ------------------------------------------------------------------------ @@ -202,7 +208,10 @@ public OverConstrainedVersionException getVersionRangeViolation( int i ) public List getVersionRangeViolations() { - return versionRangeViolations == null ? Collections.emptyList() : versionRangeViolations; + return versionRangeViolations == null + ? Collections.emptyList() + : Collections.unmodifiableList( versionRangeViolations ); + } // ------------------------------------------------------------------------ @@ -234,8 +243,10 @@ public ArtifactResolutionException getMetadataResolutionException( int i ) public List getMetadataResolutionExceptions() { - return metadataResolutionExceptions == null ? Collections.emptyList() - : metadataResolutionExceptions; + return metadataResolutionExceptions == null + ? Collections.emptyList() + : Collections.unmodifiableList( metadataResolutionExceptions ); + } // ------------------------------------------------------------------------ @@ -267,7 +278,7 @@ public List getErrorArtifactExceptions() return Collections.emptyList(); } - return errorArtifactExceptions; + return Collections.unmodifiableList( errorArtifactExceptions ); } // ------------------------------------------------------------------------ @@ -304,7 +315,7 @@ public List getCircularDependencyExceptions() return Collections.emptyList(); } - return circularDependencyExceptions; + return Collections.unmodifiableList( circularDependencyExceptions ); } // ------------------------------------------------------------------------ @@ -318,7 +329,7 @@ public List getRepositories() return Collections.emptyList(); } - return repositories; + return Collections.unmodifiableList( repositories ); } public ArtifactResolutionResult setRepositories( final List repositories ) diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java index a156871de04..8e47d2e0b42 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java @@ -102,6 +102,7 @@ public void addDependencies( Set artifacts, List r children.add( new ResolutionNode( a, remoteRepositories, this ) ); } + children = Collections.unmodifiableList( children ); } else { diff --git a/maven-core/src/main/java/org/apache/maven/exception/ExceptionSummary.java b/maven-core/src/main/java/org/apache/maven/exception/ExceptionSummary.java index dcc376a4b9f..6615af61cee 100644 --- a/maven-core/src/main/java/org/apache/maven/exception/ExceptionSummary.java +++ b/maven-core/src/main/java/org/apache/maven/exception/ExceptionSummary.java @@ -53,7 +53,10 @@ public ExceptionSummary( Throwable exception, String message, String reference, this.exception = exception; this.message = ( message != null ) ? message : ""; this.reference = ( reference != null ) ? reference : ""; - this.children = ( children != null ) ? children : Collections.emptyList(); + this.children = ( children != null ) + ? Collections.unmodifiableList( children ) + : Collections.emptyList(); + } public Throwable getException() diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java index 87d86766271..112a064923a 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java +++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java @@ -64,8 +64,10 @@ public MavenExecutionResult setTopologicallySortedProjects( List t public List getTopologicallySortedProjects() { - return null == topologicallySortedProjects ? Collections.emptyList() - : topologicallySortedProjects; + return null == topologicallySortedProjects + ? Collections.emptyList() + : Collections.unmodifiableList( topologicallySortedProjects ); + } public DependencyResolutionResult getDependencyResolutionResult() 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 766aed14691..b78f54dc42f 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 @@ -105,32 +105,34 @@ private void collectDependencyRequirements( Set scopesToResolve, Set toScopes( String classpath ) { + Collection scopes = Collections.emptyList(); + if ( StringUtils.isNotEmpty( classpath ) ) { if ( Artifact.SCOPE_COMPILE.equals( classpath ) ) { - return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED ); + scopes = Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED ); } else if ( Artifact.SCOPE_RUNTIME.equals( classpath ) ) { - return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME ); + scopes = Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME ); } else if ( Artifact.SCOPE_COMPILE_PLUS_RUNTIME.equals( classpath ) ) { - return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, - Artifact.SCOPE_RUNTIME ); + scopes = Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, + Artifact.SCOPE_RUNTIME ); } else if ( Artifact.SCOPE_RUNTIME_PLUS_SYSTEM.equals( classpath ) ) { - return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME ); + scopes = Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME ); } else if ( Artifact.SCOPE_TEST.equals( classpath ) ) { - return Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, - Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST ); + scopes = Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, + Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST ); } } - return Collections.emptyList(); + return Collections.unmodifiableCollection( scopes ); } public void execute( MavenSession session, List mojoExecutions, ProjectIndex projectIndex ) 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 34b3b17bf62..54fa5c0defc 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 @@ -460,7 +460,7 @@ private List toMavenArtifacts( DependencyNode root, PreorderNodeListGe it.remove(); } } - return artifacts; + return Collections.unmodifiableList( artifacts ); } private Map calcImports( MavenProject project, ClassLoader parent, List imports ) diff --git a/maven-core/src/main/java/org/apache/maven/plugin/prefix/DefaultPluginPrefixRequest.java b/maven-core/src/main/java/org/apache/maven/plugin/prefix/DefaultPluginPrefixRequest.java index 7ab86cfd164..01194c866da 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/prefix/DefaultPluginPrefixRequest.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/prefix/DefaultPluginPrefixRequest.java @@ -100,7 +100,7 @@ public DefaultPluginPrefixRequest setPluginGroups( List pluginGroups ) { if ( pluginGroups != null ) { - this.pluginGroups = pluginGroups; + this.pluginGroups = Collections.unmodifiableList( pluginGroups ); } else { @@ -131,7 +131,7 @@ public DefaultPluginPrefixRequest setRepositories( List reposi { if ( repositories != null ) { - this.repositories = repositories; + this.repositories = Collections.unmodifiableList( repositories ); } else { diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/DefaultPluginVersionRequest.java b/maven-core/src/main/java/org/apache/maven/plugin/version/DefaultPluginVersionRequest.java index 9907066b9d9..57f4250c631 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/version/DefaultPluginVersionRequest.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/version/DefaultPluginVersionRequest.java @@ -140,7 +140,7 @@ public DefaultPluginVersionRequest setRepositories( List repos { if ( repositories != null ) { - this.repositories = repositories; + this.repositories = Collections.unmodifiableList( repositories ); } else { diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionResult.java b/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionResult.java index dbdf25261d6..509e8b48d9c 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionResult.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionResult.java @@ -98,7 +98,10 @@ public void setCollectionErrors( List exceptions ) public List getResolutionErrors( Dependency dependency ) { List errors = resolutionErrors.get( dependency ); - return ( errors != null ) ? errors : Collections.emptyList(); + return ( errors != null ) + ? Collections.unmodifiableList( errors ) + : Collections.emptyList(); + } public void setResolutionErrors( Dependency dependency, List errors ) 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 279399add81..95155910645 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 @@ -809,6 +809,7 @@ private void initProject( MavenProject project, Map projec map.put( d.getManagementKey(), artifact ); } } + map = Collections.unmodifiableMap( map ); } else { diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectRealmCache.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectRealmCache.java index a14e624af87..15681b6c39a 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectRealmCache.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectRealmCache.java @@ -51,7 +51,9 @@ protected static class CacheKey public CacheKey( List extensionRealms ) { - this.extensionRealms = ( extensionRealms != null ) ? extensionRealms : Collections.emptyList(); + this.extensionRealms = ( extensionRealms != null ) + ? Collections.unmodifiableList( extensionRealms ) + : Collections.emptyList(); this.hashCode = this.extensionRealms.hashCode(); } 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 80a51935ea5..7b9aead25cb 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 @@ -778,7 +778,7 @@ public List getBuildPlugins() { return Collections.emptyList(); } - return getModel().getBuild().getPlugins(); + return Collections.unmodifiableList( getModel().getBuild().getPlugins() ); } public List getModules() @@ -1079,7 +1079,7 @@ public List getBuildExtensions() } else { - return build.getExtensions(); + return Collections.unmodifiableList( build.getExtensions() ); } } @@ -1604,7 +1604,7 @@ public List getCompileDependencies() { // TODO let the scope handler deal with this if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_PROVIDED.equals( a.getScope() ) - || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) ) + || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) ) { Dependency dependency = new Dependency(); @@ -1618,7 +1618,7 @@ public List getCompileDependencies() list.add( dependency ); } } - return list; + return Collections.unmodifiableList( list ); } @Deprecated @@ -1662,7 +1662,7 @@ public List getTestDependencies() list.add( dependency ); } - return list; + return Collections.unmodifiableList( list ); } @Deprecated // used by the Maven ITs @@ -1677,7 +1677,7 @@ public List getRuntimeDependencies() List list = new ArrayList<>( artifacts.size() ); - for ( Artifact a : getArtifacts() ) + for ( Artifact a : getArtifacts() ) { // TODO let the scope handler deal with this if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_RUNTIME.equals( a.getScope() ) ) @@ -1694,7 +1694,7 @@ public List getRuntimeDependencies() list.add( dependency ); } } - return list; + return Collections.unmodifiableList( list ); } @Deprecated @@ -1790,7 +1790,7 @@ public List getSystemDependencies() list.add( dependency ); } } - return list; + return Collections.unmodifiableList( list ); } @Deprecated @@ -1862,8 +1862,7 @@ public List getReportPlugins() { return Collections.emptyList(); } - return getModel().getReporting().getPlugins(); - + return Collections.unmodifiableList( getModel().getReporting().getPlugins() ); } @Deprecated diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java index 8556a6af64d..46e56dc4709 100644 --- a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java +++ b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java @@ -58,8 +58,11 @@ public List getDependencies() public List getManagedDependencies() { - DependencyManagement depMgmt = project.getDependencyManagement(); - return ( depMgmt != null ) ? depMgmt.getDependencies() : Collections.emptyList(); + DependencyManagement depMngt = project.getDependencyManagement(); + return ( depMngt != null ) + ? Collections.unmodifiableList( depMngt.getDependencies() ) + : Collections.emptyList(); + } static class PomArtifactHandler 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 ac8081e71d4..4e4624607c0 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 @@ -772,7 +772,9 @@ protected void configure() BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class ); - return resolver.loadCoreExtensions( request, providedArtifacts, extensions ); + return Collections.unmodifiableList( resolver.loadCoreExtensions( request, providedArtifacts, + extensions ) ); + } finally { diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingException.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingException.java index 434cb591a27..b5274382be5 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingException.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingException.java @@ -136,7 +136,7 @@ public List getProblems() { return Collections.emptyList(); } - return result.getProblems(); + return Collections.unmodifiableList( result.getProblems() ); } private static String toMessage( ModelBuildingResult result ) From 5aca687c53f4b19f08e8d2141de2ed22dd7e199a Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sat, 30 Jan 2016 19:17:34 +0100 Subject: [PATCH 10/21] [MNG-4463] Dependency management import should support version ranges. Closes #64 without merging. ITs are pending to be committed. --- .../model/building/DefaultModelBuilder.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java index 44ee334c300..66687ac2753 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 @@ -1244,7 +1244,25 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque final ModelSource importSource; try { - importSource = modelResolver.resolveModel( groupId, artifactId, version ); + dependency = dependency.clone(); + importSource = modelResolver.resolveModel( dependency ); + final String resolvedId = + dependency.getGroupId() + ':' + dependency.getArtifactId() + ':' + dependency.getVersion(); + + if ( !imported.equals( resolvedId ) && importIds.contains( resolvedId ) ) + { + // A version range has been resolved to a cycle. + String message = "The dependencies of type=pom and with scope=import form a cycle: "; + for ( String modelId : importIds ) + { + message += modelId + " -> "; + } + message += resolvedId; + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ). + setMessage( message ) ); + + continue; + } } catch ( UnresolvableModelException e ) { From 48159efb2b7870571451f3c3505f75ce596192f7 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Tue, 21 Jun 2016 21:35:40 +0200 Subject: [PATCH 11/21] [MNG-5527] Dependency management import should support relocations. --- .../model/building/DefaultModelBuilder.java | 225 +++++++++++------- 1 file changed, 142 insertions(+), 83 deletions(-) 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 66687ac2753..29cc7aef2a3 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 @@ -1147,11 +1147,6 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque importIds.add( importing ); - final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver(); - final ModelResolver modelResolver = request.getModelResolver(); - - ModelBuildingRequest importRequest = null; - List importMgmts = null; for ( Iterator it = depMgmt.getDependencies().iterator(); it.hasNext(); ) @@ -1171,10 +1166,10 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque if ( groupId == null || groupId.length() <= 0 ) { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "'dependencyManagement.dependencies.dependency.groupId' for " - + dependency.getManagementKey() + " is missing." ) - .setLocation( dependency.getLocation( "" ) ) ); + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ). + setMessage( "'dependencyManagement.dependencies.dependency.groupId' for " + + dependency.getManagementKey() + " is missing." ). + setLocation( dependency.getLocation( "" ) ) ); continue; } if ( artifactId == null || artifactId.length() <= 0 ) @@ -1214,122 +1209,186 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque if ( importMgmt == null ) { - if ( workspaceResolver == null && modelResolver == null ) + if ( request.getWorkspaceModelResolver() == null && request.getModelResolver() == null ) { throw new NullPointerException( String.format( "request.workspaceModelResolver and request.modelResolver cannot be null" - + " (parent POM %s and POM %s)", + + " (parent POM %s and POM %s)", ModelProblemUtils.toId( groupId, artifactId, version ), ModelProblemUtils.toSourceHint( model ) ) ); } Model importModel = null; - if ( workspaceResolver != null ) + if ( request.getWorkspaceModelResolver() != null ) { try { - importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version ); + importModel = + request.getWorkspaceModelResolver().resolveEffectiveModel( groupId, artifactId, version ); + } catch ( UnresolvableModelException e ) { - problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) - .setMessage( e.getMessage().toString() ).setException( e ) ); + problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ). + setMessage( e.getMessage() ). + setException( e ) ); + continue; } } - // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) if ( importModel == null ) { - final ModelSource importSource; - try - { - dependency = dependency.clone(); - importSource = modelResolver.resolveModel( dependency ); - final String resolvedId = - dependency.getGroupId() + ':' + dependency.getArtifactId() + ':' + dependency.getVersion(); + // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) + importModel = this.buildImportModelFromRepository( request, dependency, importIds, problems ); - if ( !imported.equals( resolvedId ) && importIds.contains( resolvedId ) ) - { - // A version range has been resolved to a cycle. - String message = "The dependencies of type=pom and with scope=import form a cycle: "; - for ( String modelId : importIds ) - { - message += modelId + " -> "; - } - message += resolvedId; - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ). - setMessage( message ) ); - - continue; - } - } - catch ( UnresolvableModelException e ) + if ( importModel == null ) { - StringBuilder buffer = new StringBuilder( 256 ); - buffer.append( "Non-resolvable import POM" ); - if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) ) - { - buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) ); - } - buffer.append( ": " ).append( e.getMessage() ); - - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) ) - .setException( e ) ); continue; } + } - if ( importRequest == null ) - { - importRequest = new DefaultModelBuildingRequest(); - importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL ); - importRequest.setModelCache( request.getModelCache() ); - importRequest.setSystemProperties( request.getSystemProperties() ); - importRequest.setUserProperties( request.getUserProperties() ); - importRequest.setLocationTracking( request.isLocationTracking() ); - } + importMgmt = importModel.getDependencyManagement() == null + ? new DependencyManagement() + : importModel.getDependencyManagement(); - importRequest.setModelSource( importSource ); - importRequest.setModelResolver( modelResolver.newCopy() ); + putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt ); + } - final ModelBuildingResult importResult; - try - { - importResult = build( importRequest ); - } - catch ( ModelBuildingException e ) - { - problems.addAll( e.getProblems() ); - continue; - } + if ( importMgmts == null ) + { + importMgmts = new ArrayList<>(); + } - problems.addAll( importResult.getProblems() ); + importMgmts.add( importMgmt ); + } - importModel = importResult.getEffectiveModel(); - } + importIds.remove( importing ); - importMgmt = importModel.getDependencyManagement(); + dependencyManagementImporter.importManagement( model, importMgmts, request, problems ); + } - if ( importMgmt == null ) + private Model buildImportModelFromRepository( final ModelBuildingRequest targetModelBuildingRequest, + final Dependency dependency, final Collection importIds, + final DefaultModelProblemCollector problems ) + { + try + { + final String imported = + String.format( "%s:%s:%s", dependency.getGroupId(), dependency.getArtifactId(), + dependency.getVersion() ); + + final Dependency resolvedDependency = dependency.clone(); + final ModelSource importSource = + targetModelBuildingRequest.getModelResolver().resolveModel( resolvedDependency ); + + final String resolvedId = + String.format( "%s:%s:%s", resolvedDependency.getGroupId(), resolvedDependency.getArtifactId(), + resolvedDependency.getVersion() ); + + if ( !imported.equals( resolvedId ) && importIds.contains( resolvedId ) ) + { + // A version range has been resolved to a cycle. + String message = "The dependencies of type=pom and scope=" + dependency.getScope() + " form a cycle: "; + for ( String modelId : importIds ) + { + message += modelId + " -> "; + } + message += resolvedId; + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) ); + } + else + { + final ModelBuildingRequest importRequest = new DefaultModelBuildingRequest(); + importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL ); + importRequest.setModelCache( targetModelBuildingRequest.getModelCache() ); + importRequest.setSystemProperties( targetModelBuildingRequest.getSystemProperties() ); + importRequest.setUserProperties( targetModelBuildingRequest.getUserProperties() ); + importRequest.setLocationTracking( targetModelBuildingRequest.isLocationTracking() ); + importRequest.setModelSource( importSource ); + importRequest.setModelResolver( targetModelBuildingRequest.getModelResolver().newCopy() ); + + final ModelBuildingResult importResult = build( importRequest ); + problems.addAll( importResult.getProblems() ); + + Model importModel = importResult.getEffectiveModel(); + + if ( importModel.getDistributionManagement() != null + && importModel.getDistributionManagement().getRelocation() != null ) { - importMgmt = new DependencyManagement(); + final Dependency relocated = dependency.clone(); + relocated.setGroupId( importModel.getDistributionManagement().getRelocation().getGroupId() ); + relocated.setArtifactId( importModel.getDistributionManagement().getRelocation().getArtifactId() ); + relocated.setVersion( importModel.getDistributionManagement().getRelocation().getVersion() ); + + // Message below is checked for in the MNG-5527 core IT. + String message = String.format( + "The dependency of type='%s' and scope='%s' has been relocated to '%s:%s:%s'", + dependency.getType(), dependency.getScope(), relocated.getGroupId(), + relocated.getArtifactId(), relocated.getVersion() ); + + if ( importModel.getDistributionManagement().getRelocation().getMessage() != null ) + { + message += ". " + importModel.getDistributionManagement().getRelocation().getMessage(); + } + + problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE ). + setMessage( message ). + setLocation( importModel.getDistributionManagement().getRelocation().getLocation( "" ) ) ); + + importModel = this.buildImportModelFromRepository( + targetModelBuildingRequest, relocated, importIds, problems ); + } - putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt ); + return importModel; } + } + catch ( final UnresolvableModelException e ) + { + final StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( "Non-resolvable " ).append( dependency.getScope() ).append( " POM" ); - if ( importMgmts == null ) + if ( !containsCoordinates( e.getMessage(), dependency.getGroupId(), dependency.getArtifactId(), + dependency.getVersion() ) ) { - importMgmts = new ArrayList<>(); + buffer.append( ' ' ).append( ModelProblemUtils.toId( + dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() ) ); + } - importMgmts.add( importMgmt ); + buffer.append( ": " ).append( e.getMessage() ); + + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ). + setMessage( buffer.toString() ). + setLocation( dependency.getLocation( "" ) ). + setException( e ) ); + } + catch ( final ModelBuildingException e ) + { + final StringBuilder buffer = new StringBuilder( 256 ); + buffer.append( "Failure building " ).append( dependency.getScope() ).append( " POM" ); - importIds.remove( importing ); + if ( !containsCoordinates( e.getMessage(), dependency.getGroupId(), dependency.getArtifactId(), + dependency.getVersion() ) ) + { + buffer.append( ' ' ).append( ModelProblemUtils.toId( + dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() ) ); - dependencyManagementImporter.importManagement( model, importMgmts, request, problems ); + } + + buffer.append( ": " ).append( e.getMessage() ); + + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ). + setMessage( buffer.toString() ). + setLocation( dependency.getLocation( "" ) ). + setException( e ) ); + + problems.addAll( e.getProblems() ); + } + + return null; } private void putCache( ModelCache modelCache, String groupId, String artifactId, String version, From 6ee3fce524eedc74b48b3846fab2e42604a7626a Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sun, 19 Jun 2016 16:32:25 +0200 Subject: [PATCH 12/21] [MNG-5600] Dependency management import should support exclusions. --- .../model/building/DefaultModelBuilder.java | 57 +++++++++++++++---- 1 file changed, 45 insertions(+), 12 deletions(-) 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 29cc7aef2a3..4ac7baf57d5 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 @@ -19,6 +19,16 @@ * under the License. */ +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; import org.apache.commons.lang3.Validate; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; @@ -28,6 +38,7 @@ import org.apache.maven.model.Build; import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; +import org.apache.maven.model.Exclusion; import org.apache.maven.model.InputLocation; import org.apache.maven.model.InputSource; import org.apache.maven.model.Model; @@ -65,17 +76,6 @@ import org.codehaus.plexus.interpolation.MapBasedValueSource; import org.codehaus.plexus.interpolation.StringSearchInterpolator; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; - import static org.apache.maven.model.building.Result.error; import static org.apache.maven.model.building.Result.newResult; @@ -1252,7 +1252,40 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque ? new DependencyManagement() : importModel.getDependencyManagement(); - putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt ); + // [MNG-5600] Dependency management import should support exclusions. + if ( !dependency.getExclusions().isEmpty() ) + { + for ( final Exclusion exclusion : dependency.getExclusions() ) + { + if ( exclusion.getGroupId() != null && exclusion.getArtifactId() != null ) + { + for ( final Iterator dependencies = importMgmt.getDependencies().iterator(); + dependencies.hasNext(); ) + { + final Dependency candidate = dependencies.next(); + + if ( ( exclusion.getGroupId().equals( "*" ) + || exclusion.getGroupId().equals( candidate.getGroupId() ) ) + && ( exclusion.getArtifactId().equals( "*" ) + || exclusion.getArtifactId().equals( candidate.getArtifactId() ) ) ) + { + // Dependency excluded from import. + dependencies.remove(); + } + } + } + } + + for ( final Dependency includedDependency : importMgmt.getDependencies() ) + { + includedDependency.getExclusions().addAll( dependency.getExclusions() ); + } + } + else + { + // Only dependency managements without exclusion processing applied can be cached. + putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt ); + } } if ( importMgmts == null ) From 59b9f5aec54766c0d9b4d0315a10bca6bf99b5fe Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Tue, 13 Dec 2016 03:30:32 +0100 Subject: [PATCH 13/21] [MNG-4347] import-scoped dependencies of direct dependencies are not resolved using profile modifications from settings.xml o Updated the 'DefaultModelResolver' to handle replacing repositories the same way the 'DefaultDependencyCollector' does. When the 'DefaultDependencyCollector' finds a repository in a child node with an id matching a repository already in use, it will only merge any mirror definitions but never change the repository already in use. The 'DefaultModelResolver' needs to follow the same logic. What has been provided must not change for consistency. --- .../repository/internal/DefaultModelResolver.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelResolver.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelResolver.java index 68184534691..2411b4e6170 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelResolver.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelResolver.java @@ -70,6 +70,8 @@ class DefaultModelResolver private final List externalRepositories; + private final Set externalRepositoryIds; + private final ArtifactResolver resolver; private final VersionRangeResolver versionRangeResolver; @@ -92,8 +94,13 @@ class DefaultModelResolver List externalRepositories = new ArrayList<>(); externalRepositories.addAll( repositories ); this.externalRepositories = Collections.unmodifiableList( externalRepositories ); - this.repositoryIds = new HashSet<>(); + this.externalRepositoryIds = new HashSet<>(); + for ( final RemoteRepository repository : this.repositories ) + { + this.repositoryIds.add( repository.getId() ); + this.externalRepositoryIds.add( repository.getId() ); + } } private DefaultModelResolver( DefaultModelResolver original ) @@ -107,6 +114,7 @@ private DefaultModelResolver( DefaultModelResolver original ) this.repositories = new ArrayList<>( original.repositories ); this.externalRepositories = original.externalRepositories; this.repositoryIds = new HashSet<>( original.repositoryIds ); + this.externalRepositoryIds = new HashSet<>( original.externalRepositoryIds ); } @Override @@ -127,7 +135,7 @@ public void addRepository( final Repository repository, boolean replace ) if ( !repositoryIds.add( repository.getId() ) ) { - if ( !replace ) + if ( !replace || this.externalRepositoryIds.contains( repository.getId() ) ) { return; } From f2baeae3c7c79be472856ed567f1f6eb6ca5c897 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Tue, 13 Dec 2016 20:16:20 +0100 Subject: [PATCH 14/21] [MNG-5639] Support resolution of Import Scope POMs from Repo that contains a ${parameter} o Updated to stop replacing external repositories when repository merging is set to REQUEST_DOMINANT. --- .../DefaultProjectBuildingRequest.java | 19 +++++++++++-------- .../maven/project/ProjectModelResolver.java | 12 +++++++++++- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingRequest.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingRequest.java index 0451a306fc5..c7f031202f2 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingRequest.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingRequest.java @@ -83,22 +83,25 @@ public DefaultProjectBuildingRequest() pluginArtifactRepositories = new ArrayList<>(); } + @SuppressWarnings( "deprecation" ) public DefaultProjectBuildingRequest( ProjectBuildingRequest request ) { this(); - setProcessPlugins( request.isProcessPlugins() ); - setProfiles( request.getProfiles() ); setActiveProfileIds( request.getActiveProfileIds() ); + setBuildStartTime( request.getBuildStartTime() ); setInactiveProfileIds( request.getInactiveProfileIds() ); - setSystemProperties( request.getSystemProperties() ); - setUserProperties( request.getUserProperties() ); - setRemoteRepositories( request.getRemoteRepositories() ); - setPluginArtifactRepositories( request.getPluginArtifactRepositories() ); - setRepositorySession( request.getRepositorySession() ); setLocalRepository( request.getLocalRepository() ); - setBuildStartTime( request.getBuildStartTime() ); + setPluginArtifactRepositories( request.getPluginArtifactRepositories() ); + setProcessPlugins( request.isProcessPlugins() ); + setProfiles( request.getProfiles() ); setProject( request.getProject() ); + setRemoteRepositories( request.getRemoteRepositories() ); + setRepositoryMerging( request.getRepositoryMerging() ); + setRepositorySession( request.getRepositorySession() ); setResolveDependencies( request.isResolveDependencies() ); + setResolveVersionRanges( request.isResolveVersionRanges() ); + setSystemProperties( request.getSystemProperties() ); + setUserProperties( request.getUserProperties() ); setValidationLevel( request.getValidationLevel() ); } diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java b/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java index 2b3108a47fb..21d4820c4f1 100644 --- a/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java +++ b/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java @@ -77,6 +77,8 @@ public class ProjectModelResolver private final Set repositoryIds; + private final Set externalRepositoryIds; + private final ReactorModelPool modelPool; private final ProjectBuildingRequest.RepositoryMerging repositoryMerging; @@ -98,7 +100,13 @@ public ProjectModelResolver( RepositorySystemSession session, RequestTrace trace this.repositories.addAll( externalRepositories ); this.repositoryMerging = repositoryMerging; this.repositoryIds = new HashSet<>(); + this.externalRepositoryIds = new HashSet<>(); this.modelPool = modelPool; + for ( final RemoteRepository repository : repositories ) + { + this.repositoryIds.add( repository.getId() ); + this.externalRepositoryIds.add( repository.getId() ); + } } private ProjectModelResolver( ProjectModelResolver original ) @@ -112,6 +120,7 @@ private ProjectModelResolver( ProjectModelResolver original ) this.repositories = new ArrayList<>( original.repositories ); this.repositoryMerging = original.repositoryMerging; this.repositoryIds = new HashSet<>( original.repositoryIds ); + this.externalRepositoryIds = new HashSet<>( original.externalRepositoryIds ); this.modelPool = original.modelPool; } @@ -127,7 +136,8 @@ public void addRepository( final Repository repository, boolean replace ) { if ( !repositoryIds.add( repository.getId() ) ) { - if ( !replace ) + if ( !replace || ( ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT.equals( repositoryMerging ) + && this.externalRepositoryIds.contains( repository.getId() ) ) ) { return; } From 68d08667cfef52a22ab37770c19767d75767fcaf Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Thu, 18 Feb 2016 14:07:02 +0100 Subject: [PATCH 15/21] [MNG-5971] Imported dependencies should be available to inheritance processing o Updated the 'DefaultDependencyManagementImporter' to stop ignoring import dependency conflicts silently. Such conflicts need to be resolved manually by adding the conflicting dependency to the pom manually. o Updated to add support for an 'include' scope in dependency management processed before inheritance and interpolation. o Re-formatted 'DefaultModelBuilder'. o Documentation updates. --- .../model/building/DefaultModelBuilder.java | 374 +++++++++++++----- .../building/DefaultModelBuildingResult.java | 26 +- .../model/building/ModelBuildingResult.java | 12 + .../DefaultDependencyManagementImporter.java | 213 +++++++++- maven-model-builder/src/site/apt/index.apt | 12 +- 5 files changed, 522 insertions(+), 115 deletions(-) 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 4ac7baf57d5..b6acf06f95a 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 java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; @@ -86,6 +87,7 @@ public class DefaultModelBuilder implements ModelBuilder { + @Requirement private ModelProcessor modelProcessor; @@ -253,8 +255,8 @@ public ModelBuildingResult build( ModelBuildingRequest request ) DefaultProfileActivationContext profileActivationContext = getProfileActivationContext( request ); problems.setSource( "(external profiles)" ); - List activeExternalProfiles = profileSelector.getActiveProfiles( request.getProfiles(), - profileActivationContext, problems ); + List activeExternalProfiles = + profileSelector.getActiveProfiles( request.getProfiles(), profileActivationContext, problems ); result.setActiveExternalProfiles( activeExternalProfiles ); @@ -301,8 +303,9 @@ public ModelBuildingResult build( ModelBuildingRequest request ) profileActivationContext.setProjectProperties( tmpModel.getProperties() ); - List activePomProfiles = profileSelector.getActiveProfiles( rawModel.getProfiles(), - profileActivationContext, problems ); + List activePomProfiles = + profileSelector.getActiveProfiles( rawModel.getProfiles(), profileActivationContext, problems ); + currentData.setActiveProfiles( activePomProfiles ); Map interpolatedActivations = getProfileActivations( rawModel, false ); @@ -337,13 +340,13 @@ public ModelBuildingResult build( ModelBuildingRequest request ) } else if ( currentData == resultData ) { // First iteration - add initial id after version resolution. - currentData.setGroupId( currentData.getRawModel().getGroupId() == null ? parentData.getGroupId() - : currentData.getRawModel() - .getGroupId() ); + currentData.setGroupId( currentData.getRawModel().getGroupId() == null + ? parentData.getGroupId() + : currentData.getRawModel().getGroupId() ); - currentData.setVersion( currentData.getRawModel().getVersion() == null ? parentData.getVersion() - : currentData.getRawModel() - .getVersion() ); + currentData.setVersion( currentData.getRawModel().getVersion() == null + ? parentData.getVersion() + : currentData.getRawModel().getVersion() ); currentData.setArtifactId( currentData.getRawModel().getArtifactId() ); parentIds.add( currentData.getId() ); @@ -362,8 +365,9 @@ else if ( !parentIds.add( parentData.getId() ) ) } message += parentData.getId(); - problems.add( new ModelProblemCollectorRequest( ModelProblem.Severity.FATAL, ModelProblem.Version.BASE ) - .setMessage( message ) ); + problems.add( new ModelProblemCollectorRequest( ModelProblem.Severity.FATAL, + ModelProblem.Version.BASE ). + setMessage( message ) ); throw problems.newModelBuildingException(); } @@ -376,24 +380,34 @@ else if ( !parentIds.add( parentData.getId() ) ) problems.setSource( inputModel ); checkPluginVersions( lineage, request, problems ); - // inheritance assembly - assembleInheritance( lineage, request, problems ); + // [MNG-4052] import scope dependencies prefer to download pom rather than find it in the current project + // [MNG-5971] Imported dependencies should be available to inheritance processing + // + // This first phase of model building is used for building models holding just enough information to map + // groupId:artifactId:version to pom files and to provide modules to build. For this, inheritance and + // interpolation needs to be performed. A temporary model is built in phase 1 applying inheritance and + // interpolation to fill in those values but is not returned. The rest of the model building takes place in + // phase 2. + final DefaultModelProblemCollector intermediateProblems = new DefaultModelProblemCollector( result ); + final List intermediateLineage = new ArrayList<>( lineage.size() ); + for ( final ModelData modelData : lineage ) + { + intermediateLineage.add( modelData.getModel().clone() ); + } + assembleInheritance( intermediateLineage, request, intermediateProblems ); + + Model intermediateModel = intermediateLineage.get( 0 ); + intermediateModel = interpolateModel( intermediateModel, request, intermediateProblems ); Model resultModel = resultData.getModel(); + resultModel.setGroupId( intermediateModel.getGroupId() ); + resultModel.setArtifactId( intermediateModel.getArtifactId() ); + resultModel.setVersion( intermediateModel.getVersion() ); + problems.setSource( resultModel ); problems.setRootModel( resultModel ); - // model interpolation - resultModel = interpolateModel( resultModel, request, problems ); - resultData.setModel( resultModel ); - - // url normalization - modelUrlNormalizer.normalize( resultModel, request ); - - // Now the fully interpolated model is available: reconfigure the resolver - configureResolver( request.getModelResolver(), resultModel, problems, true ); - resultData.setGroupId( resultModel.getGroupId() ); resultData.setArtifactId( resultModel.getArtifactId() ); resultData.setVersion( resultModel.getVersion() ); @@ -407,6 +421,7 @@ else if ( !parentIds.add( parentData.getId() ) ) result.addModelId( modelId ); result.setActivePomProfiles( modelId, currentData.getActiveProfiles() ); result.setRawModel( modelId, currentData.getRawModel() ); + result.setEffectiveModel( modelId, currentData.getModel() ); } if ( !request.isTwoPhaseBuilding() ) @@ -420,21 +435,41 @@ else if ( !parentIds.add( parentData.getId() ) ) @Override public ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result ) throws ModelBuildingException - { - return build( request, result, new LinkedHashSet() ); - } - - private ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result, - Collection imports ) - throws ModelBuildingException { // phase 2 Model resultModel = result.getEffectiveModel(); + // Reset to on-disk values to not suppress any warnings from phase 1. + resultModel.setGroupId( result.getRawModel().getGroupId() ); + resultModel.setArtifactId( result.getRawModel().getArtifactId() ); + resultModel.setVersion( result.getRawModel().getVersion() ); + DefaultModelProblemCollector problems = new DefaultModelProblemCollector( result ); problems.setSource( resultModel ); problems.setRootModel( resultModel ); + final List lineage = new ArrayList<>( result.getModelIds().size() ); + + for ( final String modelId : result.getModelIds() ) + { + lineage.add( result.getEffectiveModel( modelId ) ); + } + + // [MNG-5971] Imported dependencies should be available to inheritance processing + processImports( lineage, "include", "pom", request, problems ); + problems.setSource( resultModel ); + + // inheritance assembly + assembleInheritance( lineage, request, problems ); + + resultModel = interpolateModel( resultModel, request, problems ); + + // url normalization + modelUrlNormalizer.normalize( resultModel, request ); + + // Now the fully interpolated model is available: reconfigure the resolver + configureResolver( request.getModelResolver(), resultModel, problems, true ); + // model path translation modelPathTranslator.alignToBaseDirectory( resultModel, resultModel.getProjectDirectory(), request ); @@ -454,8 +489,7 @@ private ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingRe lifecycleBindingsInjector.injectLifecycleBindings( resultModel, request, problems ); } - // dependency management import - importDependencyManagement( resultModel, request, problems, imports ); + this.importDependencyManagement( resultModel, "import", request, problems, new HashSet() ); // dependency management injection dependencyManagementInjector.injectManagement( resultModel, request, problems ); @@ -488,10 +522,13 @@ private ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingRe @Override public Result buildRawModel( File pomFile, int validationLevel, boolean locationTracking ) { - final ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( validationLevel ) - .setLocationTracking( locationTracking ); + final ModelBuildingRequest request = new DefaultModelBuildingRequest(). + setValidationLevel( validationLevel ). + setLocationTracking( locationTracking ); + final DefaultModelProblemCollector collector = new DefaultModelProblemCollector( new DefaultModelBuildingResult() ); + try { return newResult( readModel( null, pomFile, request, collector ), collector.getProblems() ); @@ -556,15 +593,17 @@ private Model readModel( ModelSource modelSource, File pomFile, ModelBuildingReq if ( pomFile != null ) { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.V20 ) - .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ) - .setException( e ) ); + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.V20 ). + setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ). + setException( e ) ); + } else { - problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ) - .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ) - .setException( e ) ); + problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ). + setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ). + setException( e ) ); + } } @@ -576,14 +615,16 @@ private Model readModel( ModelSource modelSource, File pomFile, ModelBuildingReq } catch ( ModelParseException e ) { - problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) - .setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() ) - .setException( e ) ); + problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ). + setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() ). + setException( e ) ); + throw problems.newModelBuildingException(); } catch ( IOException e ) { String msg = e.getMessage(); + if ( msg == null || msg.length() <= 0 ) { // NOTE: There's java.nio.charset.MalformedInputException and sun.io.MalformedInputException @@ -596,14 +637,18 @@ private Model readModel( ModelSource modelSource, File pomFile, ModelBuildingReq msg = e.getClass().getSimpleName(); } } - problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) - .setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg ).setException( e ) ); + + problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ). + setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg ). + setException( e ) ); + throw problems.newModelBuildingException(); } model.setPomFile( pomFile ); problems.setSource( model ); + modelValidator.validateRawModel( model, request, problems ); if ( hasFatalErrors( problems ) ) @@ -652,9 +697,11 @@ private void configureResolver( ModelResolver modelResolver, Model model, Defaul } catch ( InvalidRepositoryException e ) { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() ) - .setLocation( repository.getLocation( "" ) ).setException( e ) ); + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ). + setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() ). + setLocation( repository.getLocation( "" ) ). + setException( e ) ); + } } } @@ -706,21 +753,150 @@ private void checkPluginVersions( List lineage, ModelBuildingRequest if ( versions.get( key ) == null && managedVersions.get( key ) == null ) { InputLocation location = plugins.get( key ).getLocation( "" ); - problems - .add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ) - .setMessage( "'build.plugins.plugin.version' for " + key + " is missing." ) - .setLocation( location ) ); + problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ). + setMessage( "'build.plugins.plugin.version' for " + key + " is missing." ). + setLocation( location ) ); + + } + } + } + + private void processImports( final List lineage, final String scope, final String packaging, + final ModelBuildingRequest request, final DefaultModelProblemCollector problems ) + { + // [MNG-5971] Imported dependencies should be available to inheritance processing + // It's not possible to support all ${project.xyz} properties in dependency management import declarations + // because import processing is performed before the final inheritance processing is performed. So the set of + // ${project.xyz} properties supported in dependency management import declarations is limited. + + final List intermediateLineage = new ArrayList<>( lineage.size() ); + + for ( int i = 0, s0 = lineage.size(); i < s0; i++ ) + { + intermediateLineage.add( lineage.get( i ).clone() ); + } + + for ( int i = intermediateLineage.size() - 2; i >= 0; i-- ) + { + final Model parent = intermediateLineage.get( i + 1 ); + final Model child = intermediateLineage.get( i ); + + if ( child.getGroupId() == null ) + { + // Support ${project.groupId} in dependency management import declarations. + child.setGroupId( parent.getGroupId() ); + } + if ( child.getVersion() == null ) + { + // Support ${project.version} in dependency management import declarations. + child.setVersion( parent.getVersion() ); + } + + final Properties properties = new Properties(); + properties.putAll( parent.getProperties() ); + properties.putAll( child.getProperties() ); + child.setProperties( properties ); + + final List repositories = new ArrayList<>(); + repositories.addAll( child.getRepositories() ); + + for ( final Repository parentRepository : parent.getRepositories() ) + { + if ( !repositories.contains( parentRepository ) ) + { + repositories.add( parentRepository ); + } + } + + child.setRepositories( repositories ); + } + + final Properties effectiveProperties = intermediateLineage.get( 0 ).getProperties(); + + final DefaultModelProblemCollector intermediateProblems = + new DefaultModelProblemCollector( new DefaultModelBuildingResult() ); + + // Interpolates the intermediate model. + // MNG-6079: Uses the effective properties of the result model to support property overriding. + for ( int i = 0, s0 = intermediateLineage.size(); i < s0; i++ ) + { + final Model model = intermediateLineage.get( i ); + model.setProperties( effectiveProperties ); + intermediateProblems.setSource( model ); + this.interpolateModel( model, request, intermediateProblems ); + } + + // Exchanges 'include' scope dependencies in the original lineage with possibly interpolated values. + for ( int i = 0, s0 = lineage.size(); i < s0; i++ ) + { + final Model model = lineage.get( i ); + + if ( model.getDependencyManagement() != null ) + { + for ( int j = 0, s1 = model.getDependencyManagement().getDependencies().size(); j < s1; j++ ) + { + final Dependency dependency = model.getDependencyManagement().getDependencies().get( j ); + + if ( scope.equals( dependency.getScope() ) && packaging.equals( dependency.getType() ) ) + { + final Dependency interpolated = + intermediateLineage.get( i ).getDependencyManagement().getDependencies().get( j ); + + model.getDependencyManagement().getDependencies().set( j, interpolated ); + } + } } } + + // [MNG-4488] [regression] Parent POMs resolved from repository are validated in strict mode + ModelBuildingRequest lenientRequest = request; + if ( request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 ) + { + lenientRequest = new FilterModelBuildingRequest( request ) + { + + @Override + public int getValidationLevel() + { + return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0; + } + + }; + } + + // Sets up the resolver to use the effective repositories to support repository overriding. + if ( lenientRequest.getModelResolver() != null ) + { + for ( Repository repository : intermediateLineage.get( 0 ).getRepositories() ) + { + try + { + lenientRequest.getModelResolver().addRepository( repository, true ); + } + catch ( InvalidRepositoryException e ) + { + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) + .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() ) + .setLocation( repository.getLocation( "" ) ).setException( e ) ); + + } + } + } + + // Imports dependencies into the original model using the effective repositories. + for ( int i = 0, s0 = lineage.size(); i < s0; i++ ) + { + this.importDependencyManagement( lineage.get( i ), scope, lenientRequest, problems, new HashSet() ); + } } - private void assembleInheritance( List lineage, ModelBuildingRequest request, + private void assembleInheritance( List lineage, ModelBuildingRequest request, ModelProblemCollector problems ) { for ( int i = lineage.size() - 2; i >= 0; i-- ) { - Model parent = lineage.get( i + 1 ).getModel(); - Model child = lineage.get( i ).getModel(); + Model parent = lineage.get( i + 1 ); + Model child = lineage.get( i ); inheritanceAssembler.assembleModelInheritance( child, parent, request, problems ); } } @@ -858,10 +1034,11 @@ private ModelData readParent( Model childModel, ModelSource childSource, ModelBu if ( !"pom".equals( parentModel.getPackaging() ) ) { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel ) - + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" ) - .setLocation( parentModel.getLocation( "packaging" ) ) ); + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ). + setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel ) + + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" ). + setLocation( parentModel.getLocation( "packaging" ) ) ); + } } else @@ -903,11 +1080,15 @@ private ModelData readParentLocally( Model childModel, ModelSource childSource, { candidateModel = resolver.resolveRawModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() ); + } catch ( UnresolvableModelException e ) { - problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) // - .setMessage( e.getMessage().toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) ); + problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ). + setMessage( e.getMessage().toString() ). + setLocation( parent.getLocation( "" ) ). + setException( e ) ); + throw problems.newModelBuildingException(); } if ( candidateModel == null ) @@ -922,7 +1103,6 @@ private ModelData readParentLocally( Model childModel, ModelSource childSource, // have a model that is suitable, yet more checks are done here and the one for the version is problematic // before because with parents as ranges it will never work in this scenario. // - String groupId = candidateModel.getGroupId(); if ( groupId == null && candidateModel.getParent() != null ) { @@ -936,7 +1116,7 @@ private ModelData readParentLocally( Model childModel, ModelSource childSource, } if ( groupId == null || !groupId.equals( parent.getGroupId() ) || artifactId == null - || !artifactId.equals( parent.getArtifactId() ) ) + || !artifactId.equals( parent.getArtifactId() ) ) { StringBuilder buffer = new StringBuilder( 256 ); buffer.append( "'parent.relativePath'" ); @@ -949,8 +1129,10 @@ private ModelData readParentLocally( Model childModel, ModelSource childSource, buffer.append( parent.getArtifactId() ).append( ", please verify your project structure" ); problems.setSource( childModel ); - problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE ) - .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ) ); + problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE ). + setMessage( buffer.toString() ). + setLocation( parent.getLocation( "" ) ) ); + return null; } if ( version != null && parent.getVersion() != null && !version.equals( parent.getVersion() ) ) @@ -1006,7 +1188,6 @@ private ModelData readParentLocally( Model childModel, ModelSource childSource, /* * if ( version == null || !version.equals( parent.getVersion() ) ) { return null; } */ - ModelData parentData = new ModelData( candidateSource, candidateModel, groupId, artifactId, version ); return parentData; @@ -1044,7 +1225,8 @@ private ModelData readParentExternally( Model childModel, ModelBuildingRequest r ModelResolver modelResolver = request.getModelResolver(); Validate.notNull( modelResolver, "request.modelResolver cannot be null (parent POM %s and POM %s)", - ModelProblemUtils.toId( groupId, artifactId, version ), ModelProblemUtils.toSourceHint( childModel ) ); + ModelProblemUtils.toId( groupId, artifactId, version ), + ModelProblemUtils.toSourceHint( childModel ) ); ModelSource modelSource; try @@ -1077,8 +1259,11 @@ private ModelData readParentExternally( Model childModel, ModelBuildingRequest r } } - problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) - .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) ); + problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ). + setMessage( buffer.toString() ). + setLocation( parent.getLocation( "" ) ). + setException( e ) ); + throw problems.newModelBuildingException(); } @@ -1087,11 +1272,13 @@ private ModelData readParentExternally( Model childModel, ModelBuildingRequest r { lenientRequest = new FilterModelBuildingRequest( request ) { + @Override public int getValidationLevel() { return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0; } + }; } @@ -1102,8 +1289,9 @@ public int getValidationLevel() if ( childModel.getVersion() == null ) { // Message below is checked for in the MNG-2199 core IT. - problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ) - .setMessage( "Version must be a constant" ).setLocation( childModel.getLocation( "" ) ) ); + problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ). + setMessage( "Version must be a constant" ). + setLocation( childModel.getLocation( "" ) ) ); } else @@ -1111,9 +1299,9 @@ public int getValidationLevel() if ( childModel.getVersion().contains( "${" ) ) { // Message below is checked for in the MNG-2199 core IT. - problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ) - .setMessage( "Version must be a constant" ) - .setLocation( childModel.getLocation( "version" ) ) ); + problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ). + setMessage( "Version must be a constant" ). + setLocation( childModel.getLocation( "version" ) ) ); } } @@ -1133,7 +1321,7 @@ private Model getSuperModel() } @SuppressWarnings( "checkstyle:methodlength" ) - private void importDependencyManagement( Model model, ModelBuildingRequest request, + private void importDependencyManagement( Model model, String scope, ModelBuildingRequest request, DefaultModelProblemCollector problems, Collection importIds ) { DependencyManagement depMgmt = model.getDependencyManagement(); @@ -1143,6 +1331,8 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque return; } + problems.setSource( model ); + String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion(); importIds.add( importing ); @@ -1153,7 +1343,7 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque { Dependency dependency = it.next(); - if ( !"pom".equals( dependency.getType() ) || !"import".equals( dependency.getScope() ) ) + if ( !"pom".equals( dependency.getType() ) || !scope.equals( dependency.getScope() ) ) { continue; } @@ -1174,18 +1364,20 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque } if ( artifactId == null || artifactId.length() <= 0 ) { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for " - + dependency.getManagementKey() + " is missing." ) - .setLocation( dependency.getLocation( "" ) ) ); + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ). + setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for " + + dependency.getManagementKey() + " is missing." ). + setLocation( dependency.getLocation( "" ) ) ); + continue; } if ( version == null || version.length() <= 0 ) { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "'dependencyManagement.dependencies.dependency.version' for " - + dependency.getManagementKey() + " is missing." ) - .setLocation( dependency.getLocation( "" ) ) ); + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ). + setMessage( "'dependencyManagement.dependencies.dependency.version' for " + + dependency.getManagementKey() + " is missing." ). + setLocation( dependency.getLocation( "" ) ) ); + continue; } @@ -1193,14 +1385,13 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque if ( importIds.contains( imported ) ) { - String message = "The dependencies of type=pom and with scope=import form a cycle: "; + String message = "The dependencies of type=pom and scope=" + scope + " form a cycle: "; for ( String modelId : importIds ) { message += modelId + " -> "; } message += imported; problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) ); - continue; } @@ -1216,6 +1407,7 @@ private void importDependencyManagement( Model model, ModelBuildingRequest reque + " (parent POM %s and POM %s)", ModelProblemUtils.toId( groupId, artifactId, version ), ModelProblemUtils.toSourceHint( model ) ) ); + } Model importModel = null; @@ -1463,9 +1655,11 @@ private void fireEvent( Model model, ModelBuildingRequest request, ModelProblemC private boolean containsCoordinates( String message, String groupId, String artifactId, String version ) { - return message != null && ( groupId == null || message.contains( groupId ) ) - && ( artifactId == null || message.contains( artifactId ) ) - && ( version == null || message.contains( version ) ); + return message != null + && ( groupId == null || message.contains( groupId ) ) + && ( artifactId == null || message.contains( artifactId ) ) + && ( version == null || message.contains( version ) ); + } protected boolean hasModelErrors( ModelProblemCollectorExt problems ) diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java index 7c140634681..9f72fc70373 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java @@ -39,11 +39,13 @@ class DefaultModelBuildingResult private Model effectiveModel; - private List modelIds; + private final List modelIds; - private Map rawModels; + private final Map rawModels; - private Map> activePomProfiles; + private final Map effectiveModels; + + private final Map> activePomProfiles; private List activeExternalProfiles; @@ -56,6 +58,7 @@ class DefaultModelBuildingResult activePomProfiles = new HashMap<>(); activeExternalProfiles = new ArrayList<>(); problems = new ArrayList<>(); + effectiveModels = new HashMap<>(); } @Override @@ -109,6 +112,23 @@ public DefaultModelBuildingResult setRawModel( String modelId, Model rawModel ) return this; } + @Override + public Model getEffectiveModel( final String modelId ) + { + return this.effectiveModels.get( modelId ); + } + + public DefaultModelBuildingResult setEffectiveModel( final String modelId, final Model model ) + { + // Intentionally notNull because Super POM may not contain a modelId + Validate.notNull( modelId, "modelId must not be null" ); + Validate.notNull( model, "model must not be null" ); + + this.effectiveModels.put( modelId, model ); + + return this; + } + @Override public List getActivePomProfiles( String modelId ) { diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java index 44b12958ee9..b21a670aa40 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java @@ -68,6 +68,18 @@ public interface ModelBuildingResult */ Model getRawModel( String modelId ); + /** + * Gets the effective model for a given identifier. The model identifier should be from the collection obtained by + * {@link #getModelIds()}. As a special case, an empty string can be used as the identifier for the super POM. + * + * @param modelId The identifier of the desired effective model, must not be {@code null}. + * + * @return The effective model or {@code null} if the specified model id does not refer to a known model. + * + * @since 3.6 + */ + Model getEffectiveModel( String modelId ); + /** * Gets the profiles from the specified model that were active during model building. The model identifier should be * from the collection obtained by {@link #getModelIds()}. As a special case, an empty string can be used as the diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java index cce7d7f867f..b8caaa790a4 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java @@ -20,15 +20,20 @@ */ import java.util.ArrayList; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; +import org.apache.maven.model.Exclusion; +import org.apache.maven.model.InputLocation; +import org.apache.maven.model.InputSource; import org.apache.maven.model.Model; import org.apache.maven.model.building.ModelBuildingRequest; +import org.apache.maven.model.building.ModelProblem; import org.apache.maven.model.building.ModelProblemCollector; +import org.apache.maven.model.building.ModelProblemCollectorRequest; import org.codehaus.plexus.component.annotations.Component; /** @@ -42,41 +47,215 @@ public class DefaultDependencyManagementImporter { @Override - public void importManagement( Model target, List sources, - ModelBuildingRequest request, ModelProblemCollector problems ) + public void importManagement( final Model target, final List sources, + final ModelBuildingRequest request, final ModelProblemCollector problems ) { if ( sources != null && !sources.isEmpty() ) { - Map dependencies = new LinkedHashMap<>(); + final Map targetDependencies = new LinkedHashMap<>(); + final DependencyManagement targetDependencyManagement = target.getDependencyManagement() != null + ? target.getDependencyManagement() + : new DependencyManagement(); + + target.setDependencyManagement( targetDependencyManagement ); + + for ( final Dependency targetDependency : targetDependencyManagement.getDependencies() ) + { + targetDependencies.put( targetDependency.getManagementKey(), targetDependency ); + } - DependencyManagement depMgmt = target.getDependencyManagement(); + final Map> sourceDependencies = new LinkedHashMap<>(); - if ( depMgmt != null ) + for ( final DependencyManagement source : sources ) { - for ( Dependency dependency : depMgmt.getDependencies() ) + for ( final Dependency sourceDependency : source.getDependencies() ) { - dependencies.put( dependency.getManagementKey(), dependency ); + if ( !targetDependencies.containsKey( sourceDependency.getManagementKey() ) ) + { + List conflictCanditates = + sourceDependencies.get( sourceDependency.getManagementKey() ); + + if ( conflictCanditates == null ) + { + conflictCanditates = new ArrayList<>( source.getDependencies().size() ); + sourceDependencies.put( sourceDependency.getManagementKey(), conflictCanditates ); + } + + conflictCanditates.add( sourceDependency ); + } } } - else + + for ( final List conflictCanditates : sourceDependencies.values() ) { - depMgmt = new DependencyManagement(); - target.setDependencyManagement( depMgmt ); + final List conflictingDependencies = removeRedundantDependencies( conflictCanditates ); + + // First declaration wins. This is what makes the conflict resolution indeterministic because this + // solely relies on the order of declaration. There is no such thing as the "first" declaration. + targetDependencyManagement.getDependencies().add( conflictingDependencies.get( 0 ) ); + + // As of Maven 3.6, we print a warning about such conflicting imports using validation level Maven 3.1. + if ( conflictingDependencies.size() > 1 ) + { + final StringBuilder conflictsBuilder = new StringBuilder( conflictingDependencies.size() * 128 ); + + for ( final Dependency dependency : conflictingDependencies ) + { + final InputLocation location = dependency.getLocation( "" ); + + if ( location != null ) + { + final InputSource inputSource = location.getSource(); + + if ( inputSource != null ) + { + conflictsBuilder.append( ", '" ).append( inputSource.getModelId() ).append( '\'' ); + } + } + } + + problems.add( new ModelProblemCollectorRequest( + effectiveSeverity( request.getValidationLevel(), + ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 ), + ModelProblem.Version.V20 ). + setMessage( String.format( + "Dependency '%1$s' has conflicting dependency management in model '%2$s'%3$s%4$s. " + + "To resolve the conflicts, declare the dependency management for dependency '%1$s' " + + "directly in the dependency management of model '%2$s' to override what gets " + + "imported. If the Maven version in use supports it, add exclusions for the " + + "conflicting dependencies or use the include scope feature to rearrange the " + + "causing dependencies in the inheritance hierarchy applying standard override logic " + + "based on artifact coordinates. Without resolving the conflicts, your build relies " + + "on indeterministic behaviour.", + conflictingDependencies.get( 0 ).getManagementKey(), target.getId(), + target.getPomFile() != null + ? " @ '" + target.getPomFile().getAbsolutePath() + "' " + : " ", conflictsBuilder.length() > 0 + ? "(" + conflictsBuilder.substring( 2 ) + ")" + : "" ) ) ); + + } } + } + } + + private static List removeRedundantDependencies( final List candidateDependencies ) + { + final List resultDependencies = new ArrayList<>( candidateDependencies.size() ); - for ( DependencyManagement source : sources ) + while ( !candidateDependencies.isEmpty() ) + { + final Dependency resultDependency = candidateDependencies.remove( 0 ); + resultDependencies.add( resultDependency ); + + // Removes redundant dependencies. + for ( final Iterator it = candidateDependencies.iterator(); it.hasNext(); ) { - for ( Dependency dependency : source.getDependencies() ) + final Dependency candidateDependency = it.next(); + boolean redundant = true; + + redundancy_check: { - String key = dependency.getManagementKey(); - if ( !dependencies.containsKey( key ) ) + if ( !( resultDependency.getOptional() != null + ? resultDependency.getOptional().equals( candidateDependency.getOptional() ) + : candidateDependency.getOptional() == null ) ) + { + redundant = false; + break redundancy_check; + } + + if ( !( effectiveScope( resultDependency ).equals( effectiveScope( candidateDependency ) ) ) ) + { + redundant = false; + break redundancy_check; + } + + if ( !( resultDependency.getSystemPath() != null + ? resultDependency.getSystemPath().equals( candidateDependency.getSystemPath() ) + : candidateDependency.getSystemPath() == null ) ) { - dependencies.put( key, dependency ); + redundant = false; + break redundancy_check; } + + if ( !( resultDependency.getVersion() != null + ? resultDependency.getVersion().equals( candidateDependency.getVersion() ) + : candidateDependency.getVersion() == null ) ) + { + redundant = false; + break redundancy_check; + } + + for ( int i = 0, s0 = resultDependency.getExclusions().size(); i < s0; i++ ) + { + final Exclusion resultExclusion = resultDependency.getExclusions().get( i ); + + if ( !containsExclusion( candidateDependency.getExclusions(), resultExclusion ) ) + { + redundant = false; + break redundancy_check; + } + } + + for ( int i = 0, s0 = candidateDependency.getExclusions().size(); i < s0; i++ ) + { + final Exclusion candidateExclusion = candidateDependency.getExclusions().get( i ); + + if ( !containsExclusion( resultDependency.getExclusions(), candidateExclusion ) ) + { + redundant = false; + break redundancy_check; + } + } + } + + if ( redundant ) + { + it.remove(); } } + } + + return resultDependencies; + } + + private static boolean containsExclusion( final List exclusions, final Exclusion exclusion ) + { + for ( int i = 0, s0 = exclusions.size(); i < s0; i++ ) + { + final Exclusion current = exclusions.get( i ); + + if ( ( exclusion.getArtifactId() != null + ? exclusion.getArtifactId().equals( current.getArtifactId() ) + : current.getArtifactId() == null ) + && ( exclusion.getGroupId() != null + ? exclusion.getGroupId().equals( current.getGroupId() ) + : current.getGroupId() == null ) ) + { + return true; + } + } + + return false; + } - depMgmt.setDependencies( new ArrayList<>( dependencies.values() ) ); + private static String effectiveScope( final Dependency dependency ) + { + return dependency.getScope() == null + ? "compile" + : dependency.getScope(); + + } + + private static ModelProblem.Severity effectiveSeverity( final int validationLevel, final int errorThreshold ) + { + if ( validationLevel < errorThreshold ) + { + return ModelProblem.Severity.WARNING; + } + else + { + return ModelProblem.Severity.ERROR; } } diff --git a/maven-model-builder/src/site/apt/index.apt b/maven-model-builder/src/site/apt/index.apt index a14b4e3369e..9b6c8418bf5 100644 --- a/maven-model-builder/src/site/apt/index.apt +++ b/maven-model-builder/src/site/apt/index.apt @@ -57,6 +57,12 @@ Maven Model Builder ** parent resolution until {{{./super-pom.html}super-pom}} + [] + + * phase 2, with optional plugin processing + + ** dependency management include processing (for dependencies of type <<>> and scope <<>> in the <<<\>>> section) + ** inheritance assembly (see {{{./index.html#Inheritance_Assembly}below}}) ** model interpolation (see {{{./index.html#Model_Interpolation}below}}) @@ -65,10 +71,6 @@ Maven Model Builder with its <<>> implementation ({{{./xref/org/apache/maven/model/path/DefaultUrlNormalizer.html}source}}) - [] - - * phase 2, with optional plugin processing - ** model path translation: <<>> ({{{./apidocs/org/apache/maven/model/path/ModelPathTranslator.html}javadoc}}), with its <<>> implementation ({{{./xref/org/apache/maven/model/path/DefaultModelPathTranslator.html}source}}) @@ -81,7 +83,7 @@ Maven Model Builder with its <<>> implementation ({{{./xref/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.html}source}}) - ** dependency management import (for dependencies of type <<>> in the <<<\>>> section) + ** dependency management import processing (for dependencies of type <<>> and scope <<>> in the <<<\>>> section) ** dependency management injection: <<>> ({{{./apidocs/org/apache/maven/model/management/DependencyManagementInjector.html}javadoc}}), with its <<>> implementation From e409c0854cb312cd6a7e3e42620f6b60d8143a12 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Wed, 27 Jan 2016 03:46:11 +0100 Subject: [PATCH 16/21] [MNG-5227] The 'optional' flag of a dependency should be manageable. o Updated to add missing management of the optional flag to the ModelBuilder. The Maven resolver has been managing the optional flag since years. This just adds the missing parts to the ModelBuilder to make optional flag management consistent when building the effective model no matter if resolved or if build. --- .../management/DefaultDependencyManagementInjector.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultDependencyManagementInjector.java b/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultDependencyManagementInjector.java index 45474078b28..510c4cc89db 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultDependencyManagementInjector.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultDependencyManagementInjector.java @@ -85,13 +85,6 @@ public void mergeManagedDependencies( Model model ) } } - @Override - protected void mergeDependency_Optional( Dependency target, Dependency source, boolean sourceDominant, - Map context ) - { - // optional flag is not managed - } - @Override protected void mergeDependency_Exclusions( Dependency target, Dependency source, boolean sourceDominant, Map context ) From 00f7effe4e27b7025ad0fe1cbe381dbbd6e27748 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Wed, 3 Feb 2016 19:17:02 +0100 Subject: [PATCH 17/21] [MNG-1577] dependencyManagement does not work for transitive dependencies o Updated to correct an incorrect test case. --- .../src/test/resources/inheritance-repo/t06/p0/p1/pom.xml | 2 -- maven-compat/src/test/resources/inheritance-repo/t06/p0/pom.xml | 2 -- 2 files changed, 4 deletions(-) diff --git a/maven-compat/src/test/resources/inheritance-repo/t06/p0/p1/pom.xml b/maven-compat/src/test/resources/inheritance-repo/t06/p0/p1/pom.xml index 468621901e5..2ac95449d31 100644 --- a/maven-compat/src/test/resources/inheritance-repo/t06/p0/p1/pom.xml +++ b/maven-compat/src/test/resources/inheritance-repo/t06/p0/p1/pom.xml @@ -24,8 +24,6 @@ maven-test t06-d 1.0 - test - false diff --git a/maven-compat/src/test/resources/inheritance-repo/t06/p0/pom.xml b/maven-compat/src/test/resources/inheritance-repo/t06/p0/pom.xml index 60c540ca122..6a66cd16c2f 100644 --- a/maven-compat/src/test/resources/inheritance-repo/t06/p0/pom.xml +++ b/maven-compat/src/test/resources/inheritance-repo/t06/p0/pom.xml @@ -29,8 +29,6 @@ maven-test t06-d 1.2 - test - false From 5d05ac9361e9c42a772d234570d77e0ecbdc9673 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Tue, 13 Dec 2016 22:35:13 +0100 Subject: [PATCH 18/21] [MNG-5761] Dependency management is not transitive. --- .../maven/artifact/AbstractArtifactComponentTestCase.java | 4 ++-- .../plugin/internal/DefaultPluginDependenciesResolver.java | 4 ++-- .../repository/internal/MavenRepositorySystemUtils.java | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java b/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java index 0cdea195d73..8e054e52901 100644 --- a/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java +++ b/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java @@ -39,7 +39,7 @@ import org.eclipse.aether.collection.DependencyTraverser; import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory; import org.eclipse.aether.repository.LocalRepository; -import org.eclipse.aether.util.graph.manager.ClassicDependencyManager; +import org.eclipse.aether.util.graph.manager.TransitiveDependencyManager; import org.eclipse.aether.util.graph.selector.AndDependencySelector; import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector; import org.eclipse.aether.util.graph.selector.OptionalDependencySelector; @@ -349,7 +349,7 @@ protected RepositorySystemSession initRepoSession() DependencyTraverser depTraverser = new FatArtifactTraverser(); session.setDependencyTraverser( depTraverser ); - DependencyManager depManager = new ClassicDependencyManager(); + DependencyManager depManager = new TransitiveDependencyManager(); session.setDependencyManager( depManager ); DependencySelector depFilter = new AndDependencySelector( new ScopeDependencySelector( "test", "provided" ), 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 28dfb054a9f..ef09d120fe0 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 @@ -54,7 +54,7 @@ import org.eclipse.aether.util.artifact.JavaScopes; import org.eclipse.aether.util.filter.AndDependencyFilter; import org.eclipse.aether.util.filter.ScopeDependencyFilter; -import org.eclipse.aether.util.graph.manager.ClassicDependencyManager; +import org.eclipse.aether.util.graph.manager.TransitiveDependencyManager; import org.eclipse.aether.util.graph.selector.AndDependencySelector; import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer; import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy; @@ -179,7 +179,7 @@ private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact, DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session ); pluginSession.setDependencySelector( selector ); pluginSession.setDependencyGraphTransformer( transformer ); - pluginSession.setDependencyManager( new ClassicDependencyManager() ); + pluginSession.setDependencyManager( new TransitiveDependencyManager() ); CollectRequest request = new CollectRequest(); request.setRequestContext( REPOSITORY_CONTEXT ); 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 1b11cb34aa5..f6aeb115113 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 @@ -20,7 +20,6 @@ */ import java.util.Properties; - import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.artifact.DefaultArtifactType; import org.eclipse.aether.collection.DependencyGraphTransformer; @@ -33,7 +32,7 @@ import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.impl.VersionResolver; import org.eclipse.aether.util.artifact.DefaultArtifactTypeRegistry; -import org.eclipse.aether.util.graph.manager.ClassicDependencyManager; +import org.eclipse.aether.util.graph.manager.TransitiveDependencyManager; import org.eclipse.aether.util.graph.selector.AndDependencySelector; import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector; import org.eclipse.aether.util.graph.selector.OptionalDependencySelector; @@ -95,7 +94,7 @@ public static DefaultRepositorySystemSession newSession() DependencyTraverser depTraverser = new FatArtifactTraverser(); session.setDependencyTraverser( depTraverser ); - DependencyManager depManager = new ClassicDependencyManager(); + DependencyManager depManager = new TransitiveDependencyManager(); session.setDependencyManager( depManager ); DependencySelector depFilter = From 4bef93ed04540eda1419f4214e5c0ef03cdff8a1 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sun, 22 Oct 2017 06:27:47 +0200 Subject: [PATCH 19/21] [MNG-6135] Maven plugins and core extensions are not dependencies, they should be resolved the same way as projects. --- .../org/apache/maven/RepositoryUtils.java | 12 +- .../DefaultPluginDependenciesResolver.java | 305 ++++++++++++++---- .../plugin/internal/PlexusUtilsInjector.java | 30 +- .../maven/plugin/internal/WagonExcluder.java | 14 +- 4 files changed, 279 insertions(+), 82 deletions(-) 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 c1e21c44be1..4723eb1e18c 100644 --- a/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java +++ b/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java @@ -119,12 +119,16 @@ public static void toArtifacts( Collection a List nodeTrail = new ArrayList<>( trail.size() + 1 ); nodeTrail.addAll( trail ); - nodeTrail.add( artifact.getId() ); - if ( filter == null || filter.accept( node, Collections.emptyList() ) ) + if ( artifact != null ) { - artifact.setDependencyTrail( nodeTrail ); - artifacts.add( artifact ); + nodeTrail.add( artifact.getId() ); + + if ( filter == null || filter.accept( node, Collections.emptyList() ) ) + { + artifact.setDependencyTrail( nodeTrail ); + artifacts.add( artifact ); + } } toArtifacts( artifacts, node.getChildren(), nodeTrail, filter ); 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 ef09d120fe0..1e66f07a0d8 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 @@ -24,12 +24,14 @@ import java.util.Map; import org.apache.maven.RepositoryUtils; +import org.apache.maven.artifact.versioning.ComparableVersion; import org.apache.maven.model.Dependency; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.PluginResolutionException; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.logging.Logger; +import org.codehaus.plexus.util.StringUtils; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; @@ -37,6 +39,7 @@ import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.collection.DependencyCollectionContext; import org.eclipse.aether.collection.DependencyCollectionException; import org.eclipse.aether.collection.DependencyGraphTransformer; import org.eclipse.aether.collection.DependencySelector; @@ -54,8 +57,12 @@ import org.eclipse.aether.util.artifact.JavaScopes; import org.eclipse.aether.util.filter.AndDependencyFilter; import org.eclipse.aether.util.filter.ScopeDependencyFilter; +import org.eclipse.aether.util.graph.manager.ClassicDependencyManager; +import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; import org.eclipse.aether.util.graph.manager.TransitiveDependencyManager; import org.eclipse.aether.util.graph.selector.AndDependencySelector; +import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector; +import org.eclipse.aether.util.graph.selector.OptionalDependencySelector; import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer; import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy; @@ -74,6 +81,10 @@ public class DefaultPluginDependenciesResolver private static final String REPOSITORY_CONTEXT = "plugin"; + private static final String DEFAULT_PREREQUISITES = "2"; + + private static final ComparableVersion DEFAULT_RESULTION_PREREQUISITES = new ComparableVersion( "3" ); + @Requirement private Logger logger; @@ -86,50 +97,21 @@ private Artifact toArtifact( Plugin plugin, RepositorySystemSession session ) session.getArtifactTypeRegistry().get( "maven-plugin" ) ); } + @Override public Artifact resolve( Plugin plugin, List repositories, RepositorySystemSession session ) throws PluginResolutionException { - RequestTrace trace = RequestTrace.newChild( null, plugin ); - - Artifact pluginArtifact = toArtifact( plugin, session ); - - try - { - DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session ); - pluginSession.setArtifactDescriptorPolicy( new SimpleArtifactDescriptorPolicy( true, false ) ); - - ArtifactDescriptorRequest request = - new ArtifactDescriptorRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT ); - request.setTrace( trace ); - ArtifactDescriptorResult result = repoSystem.readArtifactDescriptor( pluginSession, request ); - - pluginArtifact = result.getArtifact(); - - String requiredMavenVersion = (String) result.getProperties().get( "prerequisites.maven" ); - if ( requiredMavenVersion != null ) - { - Map props = new LinkedHashMap<>( pluginArtifact.getProperties() ); - props.put( "requiredMavenVersion", requiredMavenVersion ); - pluginArtifact = pluginArtifact.setProperties( props ); - } - } - catch ( ArtifactDescriptorException e ) - { - throw new PluginResolutionException( plugin, e ); - } - try { - ArtifactRequest request = new ArtifactRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT ); - request.setTrace( trace ); - pluginArtifact = repoSystem.resolveArtifact( session, request ).getArtifact(); + final Artifact pluginArtifact = this.createPluginArtifact( plugin, session, repositories ); + final ArtifactRequest request = new ArtifactRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT ); + request.setTrace( RequestTrace.newChild( null, plugin ) ); + return this.repoSystem.resolveArtifact( session, request ).getArtifact(); } - catch ( ArtifactResolutionException e ) + catch ( ArtifactDescriptorException | ArtifactResolutionException e ) { throw new PluginResolutionException( plugin, e ); } - - return pluginArtifact; } /** @@ -151,58 +133,173 @@ public DependencyNode resolve( Plugin plugin, Artifact pluginArtifact, Dependenc session ); } - private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter, - DependencyGraphTransformer transformer, - List repositories, RepositorySystemSession session ) + @SuppressWarnings( "checkstyle:methodlength" ) + private DependencyNode resolveInternal( final Plugin plugin, final Artifact artifact, + final DependencyFilter dependencyFilter, + final DependencyGraphTransformer transformer, + final List repositories, + final RepositorySystemSession session ) throws PluginResolutionException { - RequestTrace trace = RequestTrace.newChild( null, plugin ); - - if ( pluginArtifact == null ) + // This dependency selector matches the resolver's implementation before MRESOLVER-8 got fixed. It is + // used for plugin's with prerequisites < 3.6 to mimic incorrect but backwards compatible behaviour. + class ClassicScopeDependencySelector implements DependencySelector { - pluginArtifact = toArtifact( plugin, session ); + + private final boolean transitive; + + ClassicScopeDependencySelector() + { + this( false ); + } + + private ClassicScopeDependencySelector( final boolean transitive ) + { + super(); + this.transitive = transitive; + } + + @Override + public boolean selectDependency( final org.eclipse.aether.graph.Dependency dependency ) + { + return !this.transitive + || !( "test".equals( dependency.getScope() ) + || "provided".equals( dependency.getScope() ) ); + + } + + @Override + public DependencySelector deriveChildSelector( final DependencyCollectionContext context ) + { + ClassicScopeDependencySelector child = this; + + if ( context.getDependency() != null && !child.transitive ) + { + child = new ClassicScopeDependencySelector( true ); + } + if ( context.getDependency() == null && child.transitive ) + { + child = new ClassicScopeDependencySelector( false ); + } + + return child; + } + + @Override + public boolean equals( Object obj ) + { + boolean equal = obj instanceof ClassicScopeDependencySelector; + + if ( equal ) + { + final ClassicScopeDependencySelector that = (ClassicScopeDependencySelector) obj; + equal = this.transitive == that.transitive; + } + + return equal; + } + + @Override + public int hashCode() + { + int hash = 17; + hash = hash * 31 + ( ( (Boolean) this.transitive ).hashCode() ); + return hash; + } + } - DependencyFilter collectionFilter = new ScopeDependencyFilter( "provided", "test" ); - DependencyFilter resolutionFilter = AndDependencyFilter.newInstance( collectionFilter, dependencyFilter ); + final RepositorySystemSession verboseSession; + if ( this.logger.isDebugEnabled() + && session.getConfigProperties().get( DependencyManagerUtils.CONFIG_PROP_VERBOSE ) == null ) + { + final DefaultRepositorySystemSession defaultSession = new DefaultRepositorySystemSession( session ); + defaultSession.setConfigProperty( DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE ); + verboseSession = defaultSession; + } + else + { + verboseSession = session; + } - DependencyNode node; + final RequestTrace trace = RequestTrace.newChild( null, plugin ); + final DependencyFilter collectionFilter = new ScopeDependencyFilter( "provided", "test" ); + final DependencyFilter resolutionFilter = AndDependencyFilter.newInstance( collectionFilter, dependencyFilter ); try { - DependencySelector selector = - AndDependencySelector.newInstance( session.getDependencySelector(), new WagonExcluder() ); + final Artifact pluginArtifact = artifact != null + ? this.createPluginArtifact( artifact, verboseSession, repositories ) + : this.createPluginArtifact( plugin, verboseSession, repositories ); - transformer = - ChainedDependencyGraphTransformer.newInstance( session.getDependencyGraphTransformer(), transformer ); + final ComparableVersion prerequisites = + new ComparableVersion( pluginArtifact.getProperty( "requiredMavenVersion", DEFAULT_PREREQUISITES ) ); - DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session ); - pluginSession.setDependencySelector( selector ); - pluginSession.setDependencyGraphTransformer( transformer ); - pluginSession.setDependencyManager( new TransitiveDependencyManager() ); + final boolean classicResolution = prerequisites.compareTo( DEFAULT_RESULTION_PREREQUISITES ) < 0; + + if ( this.logger.isDebugEnabled() ) + { + if ( classicResolution ) + { + this.logger.debug( String.format( + "Constructing classic plugin classpath '%s' for prerequisites '%s'.", + pluginArtifact, prerequisites ) ); + + } + else + { + this.logger.debug( String.format( + "Constructing default plugin classpath '%s' for prerequisites '%s'.", + pluginArtifact, prerequisites ) ); + + } + } + + final DependencySelector pluginDependencySelector = + classicResolution + ? new AndDependencySelector( new ClassicScopeDependencySelector(), // incorrect - see MRESOLVER-8 + new OptionalDependencySelector(), + new ExclusionDependencySelector(), + new WagonExcluder() ) + : AndDependencySelector.newInstance( verboseSession.getDependencySelector(), new WagonExcluder() ); + + final DependencyGraphTransformer pluginDependencyGraphTransformer = + ChainedDependencyGraphTransformer.newInstance( verboseSession.getDependencyGraphTransformer(), + transformer ); + + DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( verboseSession ); + pluginSession.setDependencySelector( pluginDependencySelector ); + pluginSession.setDependencyGraphTransformer( pluginDependencyGraphTransformer ); + pluginSession.setDependencyManager( classicResolution + ? new ClassicDependencyManager() + : new TransitiveDependencyManager() ); CollectRequest request = new CollectRequest(); request.setRequestContext( REPOSITORY_CONTEXT ); request.setRepositories( repositories ); - request.setRoot( new org.eclipse.aether.graph.Dependency( pluginArtifact, null ) ); + for ( Dependency dependency : plugin.getDependencies() ) { org.eclipse.aether.graph.Dependency pluginDep = - RepositoryUtils.toDependency( dependency, session.getArtifactTypeRegistry() ); + RepositoryUtils.toDependency( dependency, verboseSession.getArtifactTypeRegistry() ); + if ( !JavaScopes.SYSTEM.equals( pluginDep.getScope() ) ) { pluginDep = pluginDep.setScope( JavaScopes.RUNTIME ); } + request.addDependency( pluginDep ); request.addManagedDependency( pluginDep ); } + request.setRoot( new org.eclipse.aether.graph.Dependency( pluginArtifact, null ) ); + DependencyRequest depRequest = new DependencyRequest( request, resolutionFilter ); depRequest.setTrace( trace ); request.setTrace( RequestTrace.newChild( trace, depRequest ) ); - node = repoSystem.collectDependencies( pluginSession, request ).getRoot(); + final DependencyNode node = repoSystem.collectDependencies( pluginSession, request ).getRoot(); if ( logger.isDebugEnabled() ) { @@ -210,9 +307,10 @@ private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact, } depRequest.setRoot( node ); - repoSystem.resolveDependencies( session, depRequest ); + repoSystem.resolveDependencies( verboseSession, depRequest ); + return node; } - catch ( DependencyCollectionException e ) + catch ( ArtifactDescriptorException | DependencyCollectionException e ) { throw new PluginResolutionException( plugin, e ); } @@ -220,16 +318,59 @@ private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact, { throw new PluginResolutionException( plugin, e.getCause() ); } + } - return node; + private Artifact createPluginArtifact( final Plugin plugin, + final RepositorySystemSession session, + final List repositories ) + throws ArtifactDescriptorException + { + return this.createPluginArtifact( toArtifact( plugin, session ), session, repositories ); } + private Artifact createPluginArtifact( final Artifact artifact, + final RepositorySystemSession session, + final List repositories ) + throws ArtifactDescriptorException + { + Artifact pluginArtifact = artifact; + final DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session ); + pluginSession.setArtifactDescriptorPolicy( new SimpleArtifactDescriptorPolicy( true, false ) ); + + final ArtifactDescriptorRequest request = + new ArtifactDescriptorRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT ); + + request.setTrace( RequestTrace.newChild( null, artifact ) ); + + final ArtifactDescriptorResult result = this.repoSystem.readArtifactDescriptor( pluginSession, request ); + + pluginArtifact = result.getArtifact(); + + final String requiredMavenVersion = (String) result.getProperties().get( "prerequisites.maven" ); + + if ( requiredMavenVersion != null ) + { + final Map props = new LinkedHashMap<>( pluginArtifact.getProperties() ); + props.put( "requiredMavenVersion", requiredMavenVersion ); + pluginArtifact = pluginArtifact.setProperties( props ); + } + + return pluginArtifact; + } + + // Keep this class in sync with org.apache.maven.project.DefaultProjectDependenciesResolver.GraphLogger class GraphLogger implements DependencyVisitor { private String indent = ""; + GraphLogger() + { + super(); + } + + @Override public boolean visitEnter( DependencyNode node ) { StringBuilder buffer = new StringBuilder( 128 ); @@ -237,10 +378,53 @@ public boolean visitEnter( DependencyNode node ) org.eclipse.aether.graph.Dependency dep = node.getDependency(); if ( dep != null ) { - Artifact art = dep.getArtifact(); + org.eclipse.aether.artifact.Artifact art = dep.getArtifact(); buffer.append( art ); buffer.append( ':' ).append( dep.getScope() ); + + // TODO We currently cannot tell which section contained the management + // information. When resolver 1.1 provides this information, these log messages should be updated + // to contain it. + if ( ( node.getManagedBits() & DependencyNode.MANAGED_SCOPE ) == DependencyNode.MANAGED_SCOPE ) + { + final String premanagedScope = DependencyManagerUtils.getPremanagedScope( node ); + buffer.append( " (scope managed from " ); + buffer.append( StringUtils.defaultString( premanagedScope, "default" ) ); + buffer.append( ')' ); + } + + if ( ( node.getManagedBits() & DependencyNode.MANAGED_VERSION ) == DependencyNode.MANAGED_VERSION ) + { + final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node ); + buffer.append( " (version managed from " ); + buffer.append( StringUtils.defaultString( premanagedVersion, "default" ) ); + buffer.append( ')' ); + } + + if ( ( node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL ) == DependencyNode.MANAGED_OPTIONAL ) + { + final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional( node ); + buffer.append( " (optionality managed from " ); + buffer.append( StringUtils.defaultString( premanagedOptional, "default" ) ); + buffer.append( ')' ); + } + + if ( ( node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS ) + == DependencyNode.MANAGED_EXCLUSIONS ) + { + // TODO As of resolver 1.1, use DependencyManagerUtils.getPremanagedExclusions( node ). + // The resolver 1.0.x releases do not record premanaged state of exclusions. + buffer.append( " (exclusions managed)" ); + } + + if ( ( node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES ) + == DependencyNode.MANAGED_PROPERTIES ) + { + // TODO As of resolver 1.1, use DependencyManagerUtils.getPremanagedProperties( node ). + // The resolver 1.0.x releases do not record premanaged state of properties. + buffer.append( " (properties managed)" ); + } } logger.debug( buffer.toString() ); @@ -248,6 +432,7 @@ public boolean visitEnter( DependencyNode node ) return true; } + @Override public boolean visitLeave( DependencyNode node ) { indent = indent.substring( 0, indent.length() - 3 ); diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/PlexusUtilsInjector.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/PlexusUtilsInjector.java index 16a0b63c08e..eb369579120 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/internal/PlexusUtilsInjector.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/PlexusUtilsInjector.java @@ -64,24 +64,32 @@ public DependencyNode transformGraph( DependencyNode node, DependencyGraphTransf private DependencyNode findPlexusUtils( DependencyNode node ) { - Artifact artifact = node.getDependency().getArtifact(); + DependencyNode plexusUtils = null; - if ( AID.equals( artifact.getArtifactId() ) && GID.equals( artifact.getGroupId() ) - && EXT.equals( artifact.getExtension() ) && "".equals( artifact.getClassifier() ) ) + find: { - return node; - } + if ( AID.equals( node.getArtifact().getArtifactId() ) + && GID.equals( node.getArtifact().getGroupId() ) + && EXT.equals( node.getArtifact().getExtension() ) + && "".equals( node.getArtifact().getClassifier() ) ) + { + plexusUtils = node; + break find; + } - for ( DependencyNode child : node.getChildren() ) - { - DependencyNode result = findPlexusUtils( child ); - if ( result != null ) + for ( DependencyNode child : node.getChildren() ) { - return result; + DependencyNode result = findPlexusUtils( child ); + + if ( result != null ) + { + plexusUtils = result; + break find; + } } } - return null; + return plexusUtils; } } diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/WagonExcluder.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/WagonExcluder.java index d374cab9a54..e003ede9794 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/internal/WagonExcluder.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/WagonExcluder.java @@ -51,19 +51,19 @@ private WagonExcluder( boolean coreArtifact ) public boolean selectDependency( Dependency dependency ) { - return !coreArtifact || !isWagonProvider( dependency.getArtifact() ); + return !( coreArtifact && isWagonProvider( dependency.getArtifact() ) ); } public DependencySelector deriveChildSelector( DependencyCollectionContext context ) { - if ( coreArtifact || !isLegacyCoreArtifact( context.getDependency().getArtifact() ) ) - { - return this; - } - else + WagonExcluder child = this; + + if ( isLegacyCoreArtifact( context.getArtifact() ) && !this.coreArtifact ) { - return new WagonExcluder( true ); + child = new WagonExcluder( true ); } + + return child; } private boolean isLegacyCoreArtifact( Artifact artifact ) From 08f6050847559ead6c743a34658ce06fcff13563 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sun, 22 Oct 2017 06:04:40 +0200 Subject: [PATCH 20/21] [MNG-6141] Dependency management overrides are not transitive and should be considered an anti-pattern. --- .../AbstractArtifactComponentTestCase.java | 20 +++++++++---------- .../t10/ProjectInheritanceTest.java | 3 +-- .../inheritance-repo/t04/p0/p1/pom.xml | 11 +++++++++- .../inheritance-repo/t10/p0/p1/pom.xml | 12 ++++++++++- .../DefaultPluginDependenciesResolver.java | 4 ++-- .../internal/MavenRepositorySystemUtils.java | 5 +++-- 6 files changed, 37 insertions(+), 18 deletions(-) diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java b/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java index 8e054e52901..5d84746f995 100644 --- a/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java +++ b/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java @@ -19,6 +19,14 @@ * under the License. */ +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; @@ -39,7 +47,7 @@ import org.eclipse.aether.collection.DependencyTraverser; import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory; import org.eclipse.aether.repository.LocalRepository; -import org.eclipse.aether.util.graph.manager.TransitiveDependencyManager; +import org.eclipse.aether.util.graph.manager.DefaultDependencyManager; import org.eclipse.aether.util.graph.selector.AndDependencySelector; import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector; import org.eclipse.aether.util.graph.selector.OptionalDependencySelector; @@ -54,14 +62,6 @@ import org.eclipse.aether.util.graph.traverser.FatArtifactTraverser; import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; - /** * @author Jason van Zyl */ @@ -349,7 +349,7 @@ protected RepositorySystemSession initRepoSession() DependencyTraverser depTraverser = new FatArtifactTraverser(); session.setDependencyTraverser( depTraverser ); - DependencyManager depManager = new TransitiveDependencyManager(); + DependencyManager depManager = new DefaultDependencyManager(); session.setDependencyManager( depManager ); DependencySelector depFilter = new AndDependencySelector( new ScopeDependencySelector( "test", "provided" ), diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t10/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t10/ProjectInheritanceTest.java index c785176224b..246f6d8b95b 100644 --- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t10/ProjectInheritanceTest.java +++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t10/ProjectInheritanceTest.java @@ -87,8 +87,7 @@ public void testDependencyManagementOverridesTransitiveDependencyVersion() // transitive dep, overridden b depMgmt assertTrue("Incorrect scope for " + b.getDependencyConflictId(), b.getScope().equals("runtime")); - // direct dep, overrides depMgmt + // child depMgmt overrides parent depMgmt assertTrue("Incorrect scope for " + c.getDependencyConflictId(), c.getScope().equals("runtime")); - } } \ No newline at end of file diff --git a/maven-compat/src/test/resources/inheritance-repo/t04/p0/p1/pom.xml b/maven-compat/src/test/resources/inheritance-repo/t04/p0/p1/pom.xml index c25fc3e7388..d7320a70894 100644 --- a/maven-compat/src/test/resources/inheritance-repo/t04/p0/p1/pom.xml +++ b/maven-compat/src/test/resources/inheritance-repo/t04/p0/p1/pom.xml @@ -14,6 +14,16 @@ scm-url + + + + maven-test + t04-c + 1.0 + + + + @@ -24,7 +34,6 @@ maven-test t04-c - 1.0 diff --git a/maven-compat/src/test/resources/inheritance-repo/t10/p0/p1/pom.xml b/maven-compat/src/test/resources/inheritance-repo/t10/p0/p1/pom.xml index ed82ae1344c..15d7230be06 100644 --- a/maven-compat/src/test/resources/inheritance-repo/t10/p0/p1/pom.xml +++ b/maven-compat/src/test/resources/inheritance-repo/t10/p0/p1/pom.xml @@ -14,6 +14,17 @@ scm-url + + + + maven-test + t10-c + 1.0 + runtime + + + + @@ -24,7 +35,6 @@ maven-test t10-c - runtime 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 1e66f07a0d8..1e69c3db595 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 @@ -58,8 +58,8 @@ import org.eclipse.aether.util.filter.AndDependencyFilter; import org.eclipse.aether.util.filter.ScopeDependencyFilter; import org.eclipse.aether.util.graph.manager.ClassicDependencyManager; +import org.eclipse.aether.util.graph.manager.DefaultDependencyManager; import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; -import org.eclipse.aether.util.graph.manager.TransitiveDependencyManager; import org.eclipse.aether.util.graph.selector.AndDependencySelector; import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector; import org.eclipse.aether.util.graph.selector.OptionalDependencySelector; @@ -272,7 +272,7 @@ public int hashCode() pluginSession.setDependencyGraphTransformer( pluginDependencyGraphTransformer ); pluginSession.setDependencyManager( classicResolution ? new ClassicDependencyManager() - : new TransitiveDependencyManager() ); + : new DefaultDependencyManager() ); CollectRequest request = new CollectRequest(); request.setRequestContext( REPOSITORY_CONTEXT ); 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 f6aeb115113..2e48c430725 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 @@ -20,6 +20,7 @@ */ import java.util.Properties; + import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.artifact.DefaultArtifactType; import org.eclipse.aether.collection.DependencyGraphTransformer; @@ -32,7 +33,7 @@ import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.impl.VersionResolver; import org.eclipse.aether.util.artifact.DefaultArtifactTypeRegistry; -import org.eclipse.aether.util.graph.manager.TransitiveDependencyManager; +import org.eclipse.aether.util.graph.manager.DefaultDependencyManager; import org.eclipse.aether.util.graph.selector.AndDependencySelector; import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector; import org.eclipse.aether.util.graph.selector.OptionalDependencySelector; @@ -94,7 +95,7 @@ public static DefaultRepositorySystemSession newSession() DependencyTraverser depTraverser = new FatArtifactTraverser(); session.setDependencyTraverser( depTraverser ); - DependencyManager depManager = new TransitiveDependencyManager(); + DependencyManager depManager = new DefaultDependencyManager(); session.setDependencyManager( depManager ); DependencySelector depFilter = From 1f76bd9424737769cc8fe5c424e30ddfc14e31a5 Mon Sep 17 00:00:00 2001 From: Christian Schulte Date: Sun, 18 Mar 2018 07:57:25 +0100 Subject: [PATCH 21/21] o Pending debug log messages. --- .../DefaultPluginDependenciesResolver.java | 124 ++++++++--- .../DefaultProjectDependenciesResolver.java | 198 +++++++++++++++--- .../ArtifactDescriptorReaderDelegate.java | 72 ++++++- 3 files changed, 333 insertions(+), 61 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java index 1e69c3db595..9bfacc94f44 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 @@ -19,6 +19,7 @@ * under the License. */ +import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -288,11 +289,20 @@ public int hashCode() pluginDep = pluginDep.setScope( JavaScopes.RUNTIME ); } - request.addDependency( pluginDep ); - request.addManagedDependency( pluginDep ); + final Object sourceHint = dependency.getLocation( "" ); + request.addDependency( pluginDep.setSourceHint( sourceHint != null + ? sourceHint.toString() + : dependency.toString() ) ); + + request.addManagedDependency( pluginDep.setSourceHint( sourceHint != null + ? sourceHint.toString() + : dependency.toString() ) ); + } - request.setRoot( new org.eclipse.aether.graph.Dependency( pluginArtifact, null ) ); + final Object sourceHint = plugin.getLocation( "" ); + request.setRoot( new org.eclipse.aether.graph.Dependency( pluginArtifact, null ). + setSourceHint( sourceHint != null ? sourceHint.toString() : plugin.toString() ) ); DependencyRequest depRequest = new DependencyRequest( request, resolutionFilter ); depRequest.setTrace( trace ); @@ -370,7 +380,6 @@ class GraphLogger super(); } - @Override public boolean visitEnter( DependencyNode node ) { StringBuilder buffer = new StringBuilder( 128 ); @@ -381,49 +390,117 @@ public boolean visitEnter( DependencyNode node ) org.eclipse.aether.artifact.Artifact art = dep.getArtifact(); buffer.append( art ); - buffer.append( ':' ).append( dep.getScope() ); + buffer.append( ':' ).append( dep.getScope() ).append( ":optional(" ). + append( dep.getOptional() == null + ? "default" + : dep.isOptional() + ? "true" + : "false" ).append( ')' ); + + if ( !dep.getExclusions().isEmpty() ) + { + buffer.append( ":exclusions(" ).append( dep.getExclusions() ).append( ')' ); + } + + if ( !dep.getArtifact().getProperties().isEmpty() ) + { + buffer.append( ":properties(" ).append( dep.getArtifact().getProperties() ).append( ')' ); + } - // TODO We currently cannot tell which section contained the management - // information. When resolver 1.1 provides this information, these log messages should be updated - // to contain it. if ( ( node.getManagedBits() & DependencyNode.MANAGED_SCOPE ) == DependencyNode.MANAGED_SCOPE ) { final String premanagedScope = DependencyManagerUtils.getPremanagedScope( node ); - buffer.append( " (scope managed from " ); - buffer.append( StringUtils.defaultString( premanagedScope, "default" ) ); - buffer.append( ')' ); + if ( premanagedScope != null && !premanagedScope.equals( dep.getScope() ) ) + { + buffer.append( " (scope managed from " ); + buffer.append( StringUtils.defaultString( premanagedScope, "default" ) ); + + final String sourceHint = DependencyManagerUtils.getScopeManagementSourceHint( node ); + if ( sourceHint != null ) + { + buffer.append( " by " ).append( sourceHint ).append( ' ' ); + } + + buffer.append( ')' ); + } } if ( ( node.getManagedBits() & DependencyNode.MANAGED_VERSION ) == DependencyNode.MANAGED_VERSION ) { final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node ); - buffer.append( " (version managed from " ); - buffer.append( StringUtils.defaultString( premanagedVersion, "default" ) ); - buffer.append( ')' ); + if ( premanagedVersion != null && !premanagedVersion.equals( dep.getArtifact().getVersion() ) ) + { + buffer.append( " (version managed from " ); + buffer.append( StringUtils.defaultString( premanagedVersion, "default" ) ); + + final String sourceHint = DependencyManagerUtils.getVersionManagementSourceHint( node ); + if ( sourceHint != null ) + { + buffer.append( " by " ).append( sourceHint ).append( ' ' ); + } + + buffer.append( ')' ); + } } if ( ( node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL ) == DependencyNode.MANAGED_OPTIONAL ) { final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional( node ); - buffer.append( " (optionality managed from " ); - buffer.append( StringUtils.defaultString( premanagedOptional, "default" ) ); - buffer.append( ')' ); + if ( premanagedOptional != null && !premanagedOptional.equals( dep.getOptional() ) ) + { + buffer.append( " (optionality managed from " ); + buffer.append( StringUtils.defaultString( premanagedOptional, "default" ) ); + + final String sourceHint = DependencyManagerUtils.getOptionalityManagementSourceHint( node ); + if ( sourceHint != null ) + { + buffer.append( " by " ).append( sourceHint ).append( ' ' ); + } + + buffer.append( ')' ); + } } if ( ( node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS ) == DependencyNode.MANAGED_EXCLUSIONS ) { - // TODO As of resolver 1.1, use DependencyManagerUtils.getPremanagedExclusions( node ). - // The resolver 1.0.x releases do not record premanaged state of exclusions. - buffer.append( " (exclusions managed)" ); + final Collection premanagedExclusions = + DependencyManagerUtils.getPremanagedExclusions( node ); + + if ( premanagedExclusions != null && !premanagedExclusions.equals( dep.getExclusions() ) ) + { + buffer.append( " (exclusions managed from " ); + buffer.append( StringUtils.defaultString( premanagedExclusions, "default" ) ); + + final String sourceHint = DependencyManagerUtils.getExclusionsManagementSourceHint( node ); + if ( sourceHint != null ) + { + buffer.append( " by " ).append( sourceHint ).append( ' ' ); + } + + buffer.append( ')' ); + } } if ( ( node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES ) == DependencyNode.MANAGED_PROPERTIES ) { - // TODO As of resolver 1.1, use DependencyManagerUtils.getPremanagedProperties( node ). - // The resolver 1.0.x releases do not record premanaged state of properties. - buffer.append( " (properties managed)" ); + final Map premanagedProperties = + DependencyManagerUtils.getPremanagedProperties( node ); + + if ( premanagedProperties != null && !premanagedProperties.equals( art.getProperties() ) ) + { + buffer.append( " (properties managed from " ); + buffer.append( StringUtils.defaultString( premanagedProperties, "default" ) ); + + final String sourceHint = DependencyManagerUtils.getPropertiesManagementSourceHint( node ); + if ( sourceHint != null ) + { + buffer.append( " by " ).append( sourceHint ).append( ' ' ); + } + + buffer.append( ')' ); + } } } @@ -432,7 +509,6 @@ public boolean visitEnter( DependencyNode node ) return true; } - @Override public boolean visitLeave( DependencyNode node ) { indent = indent.substring( 0, indent.length() - 3 ); 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 4bb9609fc25..0649ea16a88 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 @@ -19,6 +19,7 @@ * under the License. */ +import java.io.File; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -29,6 +30,7 @@ import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; import org.apache.maven.model.Exclusion; +import org.apache.maven.model.Model; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.logging.Logger; @@ -80,7 +82,7 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request ) ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry(); if ( logger.isDebugEnabled() - && session.getConfigProperties().get( DependencyManagerUtils.CONFIG_PROP_VERBOSE ) == null ) + && session.getConfigProperties().get( DependencyManagerUtils.CONFIG_PROP_VERBOSE ) == null ) { DefaultRepositorySystemSession verbose = new DefaultRepositorySystemSession( session ); verbose.setConfigProperty( DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE ); @@ -106,12 +108,14 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request ) for ( Dependency dependency : project.getDependencies() ) { if ( StringUtils.isEmpty( dependency.getGroupId() ) || StringUtils.isEmpty( dependency.getArtifactId() ) - || StringUtils.isEmpty( dependency.getVersion() ) ) + || StringUtils.isEmpty( dependency.getVersion() ) ) { // guard against case where best-effort resolution for invalid models is requested continue; } - collect.addDependency( RepositoryUtils.toDependency( dependency, stereotypes ) ); + collect.addDependency( RepositoryUtils.toDependency( dependency, stereotypes ). + setSourceHint( toSourceHint( project.getModel() ) ) ); + } } else @@ -130,7 +134,7 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request ) } String key = ArtifactIdUtils.toVersionlessId( dependency.getGroupId(), dependency.getArtifactId(), - dependency.getType(), classifier ); + dependency.getType(), classifier ); dependencies.put( key, dependency ); } for ( Artifact artifact : project.getDependencyArtifacts() ) @@ -146,7 +150,7 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request ) art = art.setFile( null ).setVersion( art.getBaseVersion() ); dep = dep.setArtifact( art ); } - collect.addDependency( dep ); + collect.addDependency( dep.setSourceHint( toSourceHint( project.getModel() ) ) ); } } @@ -155,7 +159,9 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request ) { for ( Dependency dependency : depMgmt.getDependencies() ) { - collect.addManagedDependency( RepositoryUtils.toDependency( dependency, stereotypes ) ); + collect.addManagedDependency( RepositoryUtils.toDependency( dependency, stereotypes ). + setSourceHint( toSourceHint( project.getModel() ) ) ); + } } @@ -175,7 +181,7 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request ) result.setCollectionErrors( e.getResult().getExceptions() ); throw new DependencyResolutionException( result, "Could not resolve dependencies for project " - + project.getId() + ": " + e.getMessage(), e ); + + project.getId() + ": " + e.getMessage(), e ); } depRequest.setRoot( node ); @@ -187,7 +193,7 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request ) if ( !child.getRelocations().isEmpty() ) { logger.warn( "The artifact " + child.getRelocations().get( 0 ) + " has been relocated to " - + child.getDependency().getArtifact() ); + + child.getDependency().getArtifact() ); } } } @@ -206,7 +212,7 @@ public DependencyResolutionResult resolve( DependencyResolutionRequest request ) process( result, e.getResult().getArtifactResults() ); throw new DependencyResolutionException( result, "Could not resolve dependencies for project " - + project.getId() + ": " + e.getMessage(), e ); + + project.getId() + ": " + e.getMessage(), e ); } return result; @@ -228,6 +234,67 @@ private void process( DefaultDependencyResolutionResult result, Collection 0 ) ? groupId : "[unknown-group-id]" ); + idBuilder.append( ':' ); + idBuilder.append( ( artifactId != null && artifactId.length() > 0 ) ? artifactId : "[unknown-artifact-id]" ); + idBuilder.append( ':' ); + idBuilder.append( ( version != null && version.length() > 0 ) ? version : "[unknown-version]" ); + + return idBuilder.toString(); + } + class GraphLogger implements DependencyVisitor { @@ -251,54 +318,117 @@ public boolean visitEnter( DependencyNode node ) org.eclipse.aether.artifact.Artifact art = dep.getArtifact(); buffer.append( art ); - buffer.append( ':' ).append( dep.getScope() ); + buffer.append( ':' ).append( dep.getScope() ).append( ":optional(" ). + append( dep.getOptional() == null + ? "default" + : dep.isOptional() + ? "true" + : "false" ).append( ')' ); + + if ( !dep.getExclusions().isEmpty() ) + { + buffer.append( ":exclusions(" ).append( dep.getExclusions() ).append( ')' ); + } + + if ( !dep.getArtifact().getProperties().isEmpty() ) + { + buffer.append( ":properties(" ).append( dep.getArtifact().getProperties() ).append( ')' ); + } - // TODO We currently cannot tell which section contained the management - // information. When resolver 1.1 provides this information, these log messages should be updated - // to contain it. if ( ( node.getManagedBits() & DependencyNode.MANAGED_SCOPE ) == DependencyNode.MANAGED_SCOPE ) { final String premanagedScope = DependencyManagerUtils.getPremanagedScope( node ); - buffer.append( " (scope managed from " ); - buffer.append( StringUtils.defaultString( premanagedScope, "default" ) ); - buffer.append( ')' ); + if ( premanagedScope != null && !premanagedScope.equals( dep.getScope() ) ) + { + buffer.append( " (scope managed from " ); + buffer.append( StringUtils.defaultString( premanagedScope, "default" ) ); + + final String sourceHint = DependencyManagerUtils.getScopeManagementSourceHint( node ); + if ( sourceHint != null ) + { + buffer.append( " by " ).append( sourceHint ).append( ' ' ); + } + + buffer.append( ')' ); + } } if ( ( node.getManagedBits() & DependencyNode.MANAGED_VERSION ) == DependencyNode.MANAGED_VERSION ) { final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node ); - buffer.append( " (version managed from " ); - buffer.append( StringUtils.defaultString( premanagedVersion, "default" ) ); - buffer.append( ')' ); + if ( premanagedVersion != null && !premanagedVersion.equals( dep.getArtifact().getVersion() ) ) + { + buffer.append( " (version managed from " ); + buffer.append( StringUtils.defaultString( premanagedVersion, "default" ) ); + + final String sourceHint = DependencyManagerUtils.getVersionManagementSourceHint( node ); + if ( sourceHint != null ) + { + buffer.append( " by " ).append( sourceHint ).append( ' ' ); + } + + buffer.append( ')' ); + } } if ( ( node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL ) == DependencyNode.MANAGED_OPTIONAL ) { final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional( node ); - buffer.append( " (optionality managed from " ); - buffer.append( StringUtils.defaultString( premanagedOptional, "default" ) ); - buffer.append( ')' ); + if ( premanagedOptional != null && !premanagedOptional.equals( dep.getOptional() ) ) + { + buffer.append( " (optionality managed from " ); + buffer.append( StringUtils.defaultString( premanagedOptional, "default" ) ); + + final String sourceHint = DependencyManagerUtils.getOptionalityManagementSourceHint( node ); + if ( sourceHint != null ) + { + buffer.append( " by " ).append( sourceHint ).append( ' ' ); + } + + buffer.append( ')' ); + } } if ( ( node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS ) - == DependencyNode.MANAGED_EXCLUSIONS ) + == DependencyNode.MANAGED_EXCLUSIONS ) { - // TODO As of resolver 1.1, use DependencyManagerUtils.getPremanagedExclusions( node ). - // The resolver 1.0.x releases do not record premanaged state of exclusions. - buffer.append( " (exclusions managed)" ); + final Collection premanagedExclusions = + DependencyManagerUtils.getPremanagedExclusions( node ); + + if ( premanagedExclusions != null && !premanagedExclusions.equals( dep.getExclusions() ) ) + { + buffer.append( " (exclusions managed from " ); + buffer.append( StringUtils.defaultString( premanagedExclusions, "default" ) ); + + final String sourceHint = DependencyManagerUtils.getExclusionsManagementSourceHint( node ); + if ( sourceHint != null ) + { + buffer.append( " by " ).append( sourceHint ).append( ' ' ); + } + + buffer.append( ')' ); + } } if ( ( node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES ) - == DependencyNode.MANAGED_PROPERTIES ) + == DependencyNode.MANAGED_PROPERTIES ) { - // TODO As of resolver 1.1, use DependencyManagerUtils.getPremanagedProperties( node ). - // The resolver 1.0.x releases do not record premanaged state of properties. - buffer.append( " (properties managed)" ); - } + final Map premanagedProperties = + DependencyManagerUtils.getPremanagedProperties( node ); - if ( dep.isOptional() ) - { - buffer.append( " (optional)" ); + if ( premanagedProperties != null && !premanagedProperties.equals( art.getProperties() ) ) + { + buffer.append( " (properties managed from " ); + buffer.append( StringUtils.defaultString( premanagedProperties, "default" ) ); + + final String sourceHint = DependencyManagerUtils.getPropertiesManagementSourceHint( node ); + if ( sourceHint != null ) + { + buffer.append( " by " ).append( sourceHint ).append( ' ' ); + } + + buffer.append( ')' ); + } } } else diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java index 82192058c86..b94147b64c8 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java @@ -19,6 +19,7 @@ * under the License. */ +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -45,12 +46,13 @@ /** * Populates Aether {@link ArtifactDescriptorResult} from Maven project {@link Model}. - * + * * Note: This class is part of work in progress and can be changed or removed without notice. * @since 3.2.4 */ public class ArtifactDescriptorReaderDelegate { + public void populateResult( RepositorySystemSession session, ArtifactDescriptorResult result, Model model ) { ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry(); @@ -62,7 +64,7 @@ public void populateResult( RepositorySystemSession session, ArtifactDescriptorR for ( org.apache.maven.model.Dependency dependency : model.getDependencies() ) { - result.addDependency( convert( dependency, stereotypes ) ); + result.addDependency( convert( dependency, stereotypes ).setSourceHint( toSourceHint( model ) ) ); } DependencyManagement mgmt = model.getDependencyManagement(); @@ -70,7 +72,9 @@ public void populateResult( RepositorySystemSession session, ArtifactDescriptorR { for ( org.apache.maven.model.Dependency dependency : mgmt.getDependencies() ) { - result.addManagedDependency( convert( dependency, stereotypes ) ); + result.addManagedDependency( convert( dependency, stereotypes ). + setSourceHint( toSourceHint( model ) ) ); + } } @@ -154,4 +158,66 @@ private void setArtifactProperties( ArtifactDescriptorResult result, Model model result.setArtifact( artifact.setProperties( props ) ); } } + + private static String toSourceHint( final Model model ) + { + String sourceHint = null; + + if ( model != null ) + { + final StringBuilder sourceHintBuilder = new StringBuilder( 128 ); + + sourceHintBuilder.append( toId( model ) ); + + File pomFile = model.getPomFile(); + if ( pomFile != null ) + { + sourceHintBuilder.append( " @ " ).append( pomFile ); + } + + sourceHint = sourceHintBuilder.toString(); + } + + return sourceHint; + } + + private static String toId( final Model model ) + { + String id = null; + + if ( model != null ) + { + String groupId = model.getGroupId(); + if ( groupId == null && model.getParent() != null ) + { + groupId = model.getParent().getGroupId(); + } + + String artifactId = model.getArtifactId(); + + String version = model.getVersion(); + if ( version == null && model.getParent() != null ) + { + version = model.getParent().getVersion(); + } + + id = toId( groupId, artifactId, version ); + } + + return id; + } + + private static String toId( final String groupId, final String artifactId, final String version ) + { + final StringBuilder idBuilder = new StringBuilder( 128 ); + + idBuilder.append( ( groupId != null && groupId.length() > 0 ) ? groupId : "[unknown-group-id]" ); + idBuilder.append( ':' ); + idBuilder.append( ( artifactId != null && artifactId.length() > 0 ) ? artifactId : "[unknown-artifact-id]" ); + idBuilder.append( ':' ); + idBuilder.append( ( version != null && version.length() > 0 ) ? version : "[unknown-version]" ); + + return idBuilder.toString(); + } + }