Repository: maven Updated Branches: refs/heads/master ea73fcdb6 -> af2c42c2c
[MNG-5971] Imported dependencies should be available to inheritance processing o Updated the 'DefaultDependencyManagementImporter' to stop ignoring import dependency conflicts silently. Such conflicts must 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 Updated to add support for 'import' and 'include' scopes also for dependencies. Project: http://git-wip-us.apache.org/repos/asf/maven/repo Commit: http://git-wip-us.apache.org/repos/asf/maven/commit/af2c42c2 Tree: http://git-wip-us.apache.org/repos/asf/maven/tree/af2c42c2 Diff: http://git-wip-us.apache.org/repos/asf/maven/diff/af2c42c2 Branch: refs/heads/master Commit: af2c42c2c16b6d6f15867646fd82b224359a5910 Parents: ea73fcd Author: Christian Schulte <[email protected]> Authored: Thu Feb 18 14:07:02 2016 +0100 Committer: Christian Schulte <[email protected]> Committed: Thu Feb 18 14:39:23 2016 +0100 ---------------------------------------------------------------------- .../model/building/DefaultModelBuilder.java | 216 ++++++++++++++++++- .../building/DefaultModelBuilderFactory.java | 8 + .../maven/model/building/ModelCacheTag.java | 35 +++ .../DefaultDependenciesImporter.java | 78 +++++++ .../DefaultDependencyManagementImporter.java | 42 ++-- .../model/composition/DependenciesImporter.java | 48 +++++ 6 files changed, 401 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven/blob/af2c42c2/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java index d42bfdd..8872a5b 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 @@ -38,6 +38,7 @@ import org.apache.maven.model.Profile; import org.apache.maven.model.Repository; import org.apache.maven.model.building.ModelProblem.Severity; import org.apache.maven.model.building.ModelProblem.Version; +import org.apache.maven.model.composition.DependenciesImporter; import org.apache.maven.model.composition.DependencyManagementImporter; import org.apache.maven.model.inheritance.InheritanceAssembler; import org.apache.maven.model.interpolation.ModelInterpolator; @@ -68,6 +69,7 @@ import java.io.IOException; 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; @@ -123,6 +125,9 @@ public class DefaultModelBuilder @Requirement private DependencyManagementImporter dependencyManagementImporter; + @Requirement + private DependenciesImporter dependenciesImporter; + @Requirement( optional = true ) private LifecycleBindingsInjector lifecycleBindingsInjector; @@ -201,6 +206,12 @@ public class DefaultModelBuilder return this; } + public DefaultModelBuilder setDependenciesImporter( DependenciesImporter dependenciesImporter ) + { + this.dependenciesImporter = dependenciesImporter; + return this; + } + public DefaultModelBuilder setDependencyManagementInjector( DependencyManagementInjector depMngmntInjector ) { this.dependencyManagementInjector = depMngmntInjector; @@ -418,11 +429,11 @@ public class DefaultModelBuilder public ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result ) throws ModelBuildingException { - return build( request, result, new LinkedHashSet<String>() ); + return build( request, result, new LinkedHashSet<String>(), new LinkedHashSet<String>() ); } private ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result, - Collection<String> imports ) + Collection<String> managementImports, Collection<String> dependencyImports ) throws ModelBuildingException { // phase 2 @@ -452,7 +463,10 @@ public class DefaultModelBuilder } // dependency management import - importDependencyManagement( resultModel, request, problems, imports ); + importDependencyManagement( resultModel, "import", request, problems, managementImports ); + + // dependencies import + importDependencies( resultModel, "import", request, problems, dependencyImports ); // dependency management injection dependencyManagementInjector.injectManagement( resultModel, request, problems ); @@ -601,6 +615,10 @@ public class DefaultModelBuilder model.setPomFile( pomFile ); problems.setSource( model ); + + this.importDependencyManagement( model, "include", request, problems, new HashSet<String>() ); + this.importDependencies( model, "include", request, problems, new HashSet<String>() ); + modelValidator.validateRawModel( model, request, problems ); if ( hasFatalErrors( problems ) ) @@ -1097,7 +1115,7 @@ public class DefaultModelBuilder return superPomProvider.getSuperModel( "4.0.0" ).clone(); } - private void importDependencyManagement( Model model, ModelBuildingRequest request, + private void importDependencyManagement( Model model, String scope, ModelBuildingRequest request, DefaultModelProblemCollector problems, Collection<String> importIds ) { DependencyManagement depMngt = model.getDependencyManagement(); @@ -1122,7 +1140,7 @@ public class DefaultModelBuilder { Dependency dependency = it.next(); - if ( !"pom".equals( dependency.getType() ) || !"import".equals( dependency.getScope() ) ) + if ( !"pom".equals( dependency.getType() ) || !scope.equals( dependency.getScope() ) ) { continue; } @@ -1296,6 +1314,194 @@ public class DefaultModelBuilder dependencyManagementImporter.importManagement( model, importMngts, request, problems ); } + private void importDependencies( final Model model, final String scope, final ModelBuildingRequest request, + final DefaultModelProblemCollector problems, final Collection<String> importIds ) + { + final String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion(); + + importIds.add( importing ); + + final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver(); + final ModelResolver modelResolver = request.getModelResolver(); + + ModelBuildingRequest importRequest = null; + + List<List<? extends Dependency>> imports = null; + + for ( final Iterator<Dependency> it = model.getDependencies().iterator(); it.hasNext(); ) + { + Dependency dependency = it.next(); + + if ( !"pom".equals( dependency.getType() ) || !scope.equals( dependency.getScope() ) ) + { + continue; + } + + it.remove(); + + final String groupId = dependency.getGroupId(); + final String artifactId = dependency.getArtifactId(); + final String version = dependency.getVersion(); + + if ( groupId == null || groupId.length() <= 0 ) + { + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) + .setMessage( "'dependencies.dependency.groupId' for " + + dependency.getManagementKey() + " is missing." ) + .setLocation( dependency.getLocation( "" ) ) ); + continue; + } + if ( artifactId == null || artifactId.length() <= 0 ) + { + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) + .setMessage( "'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( "'dependencies.dependency.version' for " + + dependency.getManagementKey() + " is missing." ) + .setLocation( dependency.getLocation( "" ) ) ); + continue; + } + + final String imported = groupId + ':' + artifactId + ':' + version; + + if ( importIds.contains( imported ) ) + { + String message = "The dependencies of type=pom and with scope=import form a cycle: "; + for ( String modelId : importIds ) + { + message += modelId + " -> "; + } + message += imported; + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) ); + continue; + } + + List<? extends Dependency> importDependencies = + getCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.DEPENDENCIES ); + + if ( importDependencies == null ) + { + if ( workspaceResolver == null && modelResolver == null ) + { + throw new NullPointerException( String.format( + "request.workspaceModelResolver and request.modelResolver cannot be null" + + " (parent POM %s and POM %s)", + ModelProblemUtils.toId( groupId, artifactId, version ), + ModelProblemUtils.toSourceHint( model ) ) ); + } + + Model importModel = null; + if ( workspaceResolver != null ) + { + try + { + importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version ); + } + catch ( UnresolvableModelException e ) + { + problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) + .setMessage( e.getMessage().toString() ).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(); + + 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 ) + { + 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() ); + } + + importRequest.setModelSource( importSource ); + importRequest.setModelResolver( modelResolver.newCopy() ); + + final ModelBuildingResult importResult; + try + { + importResult = build( importRequest ); + } + catch ( ModelBuildingException e ) + { + problems.addAll( e.getProblems() ); + continue; + } + + problems.addAll( importResult.getProblems() ); + + importModel = importResult.getEffectiveModel(); + } + + importDependencies = importModel.getDependencies(); + + putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.DEPENDENCIES, + importDependencies ); + + } + + if ( imports == null ) + { + imports = new ArrayList<>(); + } + + imports.add( importDependencies ); + } + + importIds.remove( importing ); + + dependenciesImporter.importDependencies( model, imports, request, problems ); + } + private <T> void putCache( ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag, T data ) { http://git-wip-us.apache.org/repos/asf/maven/blob/af2c42c2/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java index 36a0f46..526db68 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java @@ -20,7 +20,9 @@ package org.apache.maven.model.building; */ import org.apache.maven.model.Model; +import org.apache.maven.model.composition.DefaultDependenciesImporter; import org.apache.maven.model.composition.DefaultDependencyManagementImporter; +import org.apache.maven.model.composition.DependenciesImporter; import org.apache.maven.model.composition.DependencyManagementImporter; import org.apache.maven.model.inheritance.DefaultInheritanceAssembler; import org.apache.maven.model.inheritance.InheritanceAssembler; @@ -169,6 +171,11 @@ public class DefaultModelBuilderFactory return new DefaultDependencyManagementImporter(); } + protected DependenciesImporter newDependenciesImporter() + { + return new DefaultDependenciesImporter(); + } + protected DependencyManagementInjector newDependencyManagementInjector() { return new DefaultDependencyManagementInjector(); @@ -219,6 +226,7 @@ public class DefaultModelBuilderFactory modelBuilder.setProfileSelector( newProfileSelector() ); modelBuilder.setSuperPomProvider( newSuperPomProvider() ); modelBuilder.setDependencyManagementImporter( newDependencyManagementImporter() ); + modelBuilder.setDependenciesImporter( newDependenciesImporter() ); modelBuilder.setDependencyManagementInjector( newDependencyManagementInjector() ); modelBuilder.setLifecycleBindingsInjector( newLifecycleBindingsInjector() ); modelBuilder.setPluginManagementInjector( newPluginManagementInjector() ); http://git-wip-us.apache.org/repos/asf/maven/blob/af2c42c2/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java index 8452f96..a7009b2 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java @@ -19,6 +19,9 @@ package org.apache.maven.model.building; * under the License. */ +import java.util.ArrayList; +import java.util.List; +import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; import org.apache.maven.model.Model; @@ -129,4 +132,36 @@ interface ModelCacheTag<T> }; + /** + * The tag used to denote an effective dependencies section from an imported model. + */ + ModelCacheTag<List<? extends Dependency>> DEPENDENCIES = new ModelCacheTag<List<? extends Dependency>>() + { + + @Override + public String getName() + { + return "dependencies"; + } + + @Override + public Class<List<? extends Dependency>> getType() + { + return (Class<List<? extends Dependency>>) (Class) List.class; + } + + @Override + public List<? extends Dependency> intoCache( List<? extends Dependency> data ) + { + return ( data != null ) ? new ArrayList<>( data ) : null; + } + + @Override + public List<? extends Dependency> fromCache( List<? extends Dependency> data ) + { + return intoCache( data ); + } + + }; + } http://git-wip-us.apache.org/repos/asf/maven/blob/af2c42c2/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependenciesImporter.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependenciesImporter.java b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependenciesImporter.java new file mode 100644 index 0000000..171153e --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependenciesImporter.java @@ -0,0 +1,78 @@ +package org.apache.maven.model.composition; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Model; +import org.apache.maven.model.building.ModelBuildingRequest; +import org.apache.maven.model.building.ModelProblemCollector; +import org.codehaus.plexus.component.annotations.Component; + +/** + * Handles the import of dependencies from other models into the target model. + * + * @author Christian Schulte + */ +@Component( role = DependenciesImporter.class ) +public class DefaultDependenciesImporter + implements DependenciesImporter +{ + + @Override + public void importDependencies( final Model target, final List<? extends List<? extends Dependency>> sources, + final ModelBuildingRequest request, final ModelProblemCollector problems ) + { + if ( sources != null && !sources.isEmpty() ) + { + final Map<String, Dependency> targetDependencies = new LinkedHashMap<>(); + + for ( final Dependency targetDependency : target.getDependencies() ) + { + targetDependencies.put( targetDependency.getManagementKey(), targetDependency ); + } + + final List<Dependency> sourceDependencies = new ArrayList<>( 128 ); + + for ( final List<? extends Dependency> source : sources ) + { + for ( final Dependency sourceDependency : source ) + { + if ( !targetDependencies.containsKey( sourceDependency.getManagementKey() ) ) + { + // Intentionally does not check for conflicts in the source dependencies. We want + // such conflicts to be resolved manually instead of silently getting dropped. + sourceDependencies.add( sourceDependency ); + } + } + } + + final List<Dependency> dependencies = new ArrayList<>( targetDependencies.values() ); + dependencies.addAll( sourceDependencies ); + + target.getDependencies().clear(); + target.getDependencies().addAll( dependencies ); + } + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/af2c42c2/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java ---------------------------------------------------------------------- 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 d895913..7ab0f05 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 @@ -42,41 +42,41 @@ public class DefaultDependencyManagementImporter { @Override - public void importManagement( Model target, List<? extends DependencyManagement> sources, - ModelBuildingRequest request, ModelProblemCollector problems ) + public void importManagement( final Model target, final List<? extends DependencyManagement> sources, + final ModelBuildingRequest request, final ModelProblemCollector problems ) { if ( sources != null && !sources.isEmpty() ) { - Map<String, Dependency> dependencies = new LinkedHashMap<>(); + final Map<String, Dependency> targetDependencies = new LinkedHashMap<>(); + final DependencyManagement targetDependencyManagement = target.getDependencyManagement() != null + ? target.getDependencyManagement() + : new DependencyManagement(); - DependencyManagement depMngt = target.getDependencyManagement(); - - if ( depMngt != null ) + for ( final Dependency targetDependency : targetDependencyManagement.getDependencies() ) { - for ( Dependency dependency : depMngt.getDependencies() ) - { - dependencies.put( dependency.getManagementKey(), dependency ); - } - } - else - { - depMngt = new DependencyManagement(); - target.setDependencyManagement( depMngt ); + targetDependencies.put( targetDependency.getManagementKey(), targetDependency ); } - for ( DependencyManagement source : sources ) + final List<Dependency> sourceDependencies = new ArrayList<>( 128 ); + + for ( final DependencyManagement source : sources ) { - for ( Dependency dependency : source.getDependencies() ) + for ( final Dependency sourceDependency : source.getDependencies() ) { - String key = dependency.getManagementKey(); - if ( !dependencies.containsKey( key ) ) + if ( !targetDependencies.containsKey( sourceDependency.getManagementKey() ) ) { - dependencies.put( key, dependency ); + // Intentionally does not check for conflicts in the source dependency managements. We want + // such conflicts to be resolved manually instead of silently getting dropped. + sourceDependencies.add( sourceDependency ); } } } - depMngt.setDependencies( new ArrayList<>( dependencies.values() ) ); + final List<Dependency> dependencies = new ArrayList<>( targetDependencies.values() ); + dependencies.addAll( sourceDependencies ); + + targetDependencyManagement.setDependencies( dependencies ); + target.setDependencyManagement( targetDependencyManagement ); } } http://git-wip-us.apache.org/repos/asf/maven/blob/af2c42c2/maven-model-builder/src/main/java/org/apache/maven/model/composition/DependenciesImporter.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DependenciesImporter.java b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DependenciesImporter.java new file mode 100644 index 0000000..5874f6a --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DependenciesImporter.java @@ -0,0 +1,48 @@ +package org.apache.maven.model.composition; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.List; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Model; +import org.apache.maven.model.building.ModelBuildingRequest; +import org.apache.maven.model.building.ModelProblemCollector; + +/** + * Handles the import of dependencies from other models into the target model. + * + * @author Christian Schulte + * @since 3.4 + */ +public interface DependenciesImporter +{ + + /** + * Imports the specified dependencies sections into the given target model. + * + * @param target The model into which to import the dependencies sections, must not be <code>null</code>. + * @param sources The dependencies sections to import, may be <code>null</code>. + * @param request The model building request that holds further settings, must not be {@code null}. + * @param problems The container used to collect problems that were encountered, must not be {@code null}. + */ + void importDependencies( final Model target, final List<? extends List<? extends Dependency>> sources, + final ModelBuildingRequest request, final ModelProblemCollector problems ); + +}
