http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java ---------------------------------------------------------------------- diff --git a/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java b/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java new file mode 100644 index 0000000..e2caaeb --- /dev/null +++ b/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java @@ -0,0 +1,172 @@ +/* + * 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. + */ +package org.apache.maven.graph; + +import junit.framework.TestCase; +import org.apache.maven.execution.ProjectDependencyGraph; +import org.apache.maven.model.Dependency; +import org.apache.maven.project.DuplicateProjectException; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.dag.CycleDetectedException; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Kristian Rosenvold + */ +public class DefaultProjectDependencyGraphTest + extends TestCase +{ + + private final MavenProject aProject = createA(); + + private final MavenProject depender1 = createProject( Arrays.asList( toDependency( aProject ) ), "depender1" ); + + private final MavenProject depender2 = createProject( Arrays.asList( toDependency( aProject ) ), "depender2" ); + + private final MavenProject depender3 = createProject( Arrays.asList( toDependency( aProject ) ), "depender3" ); + + private final MavenProject depender4 = + createProject( Arrays.asList( toDependency( aProject ), toDependency( depender3 ) ), "depender4" ); + + private final MavenProject transitiveOnly = + createProject( Arrays.asList( toDependency( depender3 ) ), "depender5" ); + + public void testGetSortedProjects() + throws DuplicateProjectException, CycleDetectedException + { + ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( Arrays.asList( depender1, aProject ) ); + final List<MavenProject> sortedProjects = graph.getSortedProjects(); + assertEquals( aProject, sortedProjects.get( 0 ) ); + assertEquals( depender1, sortedProjects.get( 1 ) ); + } + + public void testVerifyExpectedParentStructure() + throws CycleDetectedException, DuplicateProjectException + { + // This test verifies the baseline structure used in susequent tests. If this fails, the rest will fail. + ProjectDependencyGraph graph = threeProjectsDependingOnASingle(); + final List<MavenProject> sortedProjects = graph.getSortedProjects(); + assertEquals( aProject, sortedProjects.get( 0 ) ); + assertEquals( depender1, sortedProjects.get( 1 ) ); + assertEquals( depender2, sortedProjects.get( 2 ) ); + assertEquals( depender3, sortedProjects.get( 3 ) ); + } + + public void testVerifyThatDownsteamProjectsComeInSortedOrder() + throws CycleDetectedException, DuplicateProjectException + { + final List<MavenProject> downstreamProjects = + threeProjectsDependingOnASingle().getDownstreamProjects( aProject, true ); + assertEquals( depender1, downstreamProjects.get( 0 ) ); + assertEquals( depender2, downstreamProjects.get( 1 ) ); + assertEquals( depender3, downstreamProjects.get( 2 ) ); + } + + public void testTransitivesInOrder() + throws CycleDetectedException, DuplicateProjectException + { + final ProjectDependencyGraph graph = + new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender4, depender2, depender3, aProject ) ); + + final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, true ); + assertEquals( depender1, downstreamProjects.get( 0 ) ); + assertEquals( depender3, downstreamProjects.get( 1 ) ); + assertEquals( depender4, downstreamProjects.get( 2 ) ); + assertEquals( depender2, downstreamProjects.get( 3 ) ); + } + + public void testNonTransitivesInOrder() + throws CycleDetectedException, DuplicateProjectException + { + final ProjectDependencyGraph graph = + new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender4, depender2, depender3, aProject ) ); + + final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, false ); + assertEquals( depender1, downstreamProjects.get( 0 ) ); + assertEquals( depender3, downstreamProjects.get( 1 ) ); + assertEquals( depender4, downstreamProjects.get( 2 ) ); + assertEquals( depender2, downstreamProjects.get( 3 ) ); + } + + public void testWithTranistiveOnly() + throws CycleDetectedException, DuplicateProjectException + { + final ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( + Arrays.asList( depender1, transitiveOnly, depender2, depender3, aProject ) ); + + final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, true ); + assertEquals( depender1, downstreamProjects.get( 0 ) ); + assertEquals( depender3, downstreamProjects.get( 1 ) ); + assertEquals( transitiveOnly, downstreamProjects.get( 2 ) ); + assertEquals( depender2, downstreamProjects.get( 3 ) ); + } + + public void testWithMissingTranistiveOnly() + throws CycleDetectedException, DuplicateProjectException + { + final ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( + Arrays.asList( depender1, transitiveOnly, depender2, depender3, aProject ) ); + + final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, false ); + assertEquals( depender1, downstreamProjects.get( 0 ) ); + assertEquals( depender3, downstreamProjects.get( 1 ) ); + assertEquals( depender2, downstreamProjects.get( 2 ) ); + } + + public void testGetUpstreamProjects() + throws CycleDetectedException, DuplicateProjectException + { + ProjectDependencyGraph graph = threeProjectsDependingOnASingle(); + final List<MavenProject> downstreamProjects = graph.getUpstreamProjects( depender1, true ); + assertEquals( aProject, downstreamProjects.get( 0 ) ); + } + + private ProjectDependencyGraph threeProjectsDependingOnASingle() + throws CycleDetectedException, DuplicateProjectException + { + return new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender2, depender3, aProject ) ); + } + + private static MavenProject createA() + { + MavenProject result = new MavenProject(); + result.setGroupId( "org.apache" ); + result.setArtifactId( "A" ); + result.setVersion( "1.2" ); + return result; + } + + static Dependency toDependency( MavenProject mavenProject ) + { + final Dependency dependency = new Dependency(); + dependency.setArtifactId( mavenProject.getArtifactId() ); + dependency.setGroupId( mavenProject.getGroupId() ); + dependency.setVersion( mavenProject.getVersion() ); + return dependency; + } + + private static MavenProject createProject( List<Dependency> dependencies, String artifactId ) + { + MavenProject result = new MavenProject(); + result.setGroupId( "org.apache" ); + result.setArtifactId( artifactId ); + result.setVersion( "1.2" ); + result.setDependencies( dependencies ); + return result; + } + +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java ---------------------------------------------------------------------- diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java index 04be08b..99b07e3 100644 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java +++ b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java @@ -409,6 +409,11 @@ public class LifecycleExecutorTest { return Collections.emptyList(); } + + public java.util.List<MavenProject> getAllSortedProjects() + { + return Collections.emptyList(); + } } ); final List<String> log = new ArrayList<String>(); http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/pom.xml ---------------------------------------------------------------------- diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml index 738f64f..186e207 100644 --- a/maven-model-builder/pom.xml +++ b/maven-model-builder/pom.xml @@ -51,7 +51,10 @@ <groupId>org.apache.maven</groupId> <artifactId>maven-builder-support</artifactId> </dependency> - + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + </dependency> <dependency> <groupId>org.eclipse.sisu</groupId> <artifactId>org.eclipse.sisu.plexus</artifactId> http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/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 80effb1..52b3c9c 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,10 @@ package org.apache.maven.model.building; * under the License. */ + +import static org.apache.maven.model.building.Result.error; +import static org.apache.maven.model.building.Result.newResult; + import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -63,6 +67,7 @@ import org.apache.maven.model.profile.ProfileSelector; import org.apache.maven.model.resolution.InvalidRepositoryException; import org.apache.maven.model.resolution.ModelResolver; import org.apache.maven.model.resolution.UnresolvableModelException; +import org.apache.maven.model.resolution.WorkspaceModelResolver; import org.apache.maven.model.superpom.SuperPomProvider; import org.apache.maven.model.validation.ModelValidator; import org.codehaus.plexus.component.annotations.Component; @@ -241,8 +246,8 @@ public class DefaultModelBuilder DefaultProfileActivationContext profileActivationContext = getProfileActivationContext( request ); problems.setSource( "(external profiles)" ); - List<Profile> activeExternalProfiles = - profileSelector.getActiveProfiles( request.getProfiles(), profileActivationContext, problems ); + List<Profile> activeExternalProfiles = profileSelector.getActiveProfiles( request.getProfiles(), + profileActivationContext, problems ); result.setActiveExternalProfiles( activeExternalProfiles ); @@ -258,7 +263,11 @@ public class DefaultModelBuilder } // read and validate raw model - Model inputModel = readModel( request.getModelSource(), request.getPomFile(), request, problems ); + Model inputModel = request.getRawModel(); + if ( inputModel == null ) + { + inputModel = readModel( request.getModelSource(), request.getPomFile(), request, problems ); + } problems.setRootModel( inputModel ); @@ -272,11 +281,12 @@ public class DefaultModelBuilder { lineage.add( currentData ); - Model tmpModel = currentData.getModel(); - - Model rawModel = tmpModel.clone(); + Model rawModel = currentData.getModel(); currentData.setRawModel( rawModel ); + Model tmpModel = rawModel.clone(); + currentData.setModel( tmpModel ); + problems.setSource( tmpModel ); // model normalization @@ -284,8 +294,8 @@ public class DefaultModelBuilder profileActivationContext.setProjectProperties( tmpModel.getProperties() ); - List<Profile> activePomProfiles = - profileSelector.getActiveProfiles( rawModel.getProfiles(), profileActivationContext, problems ); + List<Profile> activePomProfiles = profileSelector.getActiveProfiles( rawModel.getProfiles(), + profileActivationContext, problems ); currentData.setActiveProfiles( activePomProfiles ); Map<String, Activation> interpolatedActivations = getProfileActivations( rawModel, false ); @@ -320,13 +330,13 @@ public class DefaultModelBuilder } else if ( currentData == resultData ) { // First iteration - add initial parent 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() ); @@ -345,9 +355,8 @@ public class DefaultModelBuilder } 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,7 +385,7 @@ public class DefaultModelBuilder modelUrlNormalizer.normalize( resultModel, request ); // Now the fully interpolated model is available: reconfigure the resolver - configureResolver( request.getModelResolver(), resultModel, problems , true ); + configureResolver( request.getModelResolver(), resultModel, problems, true ); resultData.setGroupId( resultModel.getGroupId() ); resultData.setArtifactId( resultModel.getArtifactId() ); @@ -469,6 +478,23 @@ public class DefaultModelBuilder return result; } + @Override + public Result<? extends Model> buildRawModel( File pomFile, int validationLevel, boolean 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() ); + } + catch ( ModelBuildingException e ) + { + return error( collector.getProblems() ); + } + } + private Model readModel( ModelSource modelSource, File pomFile, ModelBuildingRequest request, DefaultModelProblemCollector problems ) throws ModelBuildingException @@ -524,14 +550,14 @@ public class DefaultModelBuilder if ( pomFile != null ) { problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.V20 ) - .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ) - .setException( e ) ); + .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 ) ); + .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ) + .setException( e ) ); } } @@ -544,8 +570,8 @@ public class DefaultModelBuilder catch ( ModelParseException e ) { problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) - .setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() ) - .setException( e ) ); + .setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() ) + .setException( e ) ); throw problems.newModelBuildingException(); } catch ( IOException e ) @@ -564,8 +590,7 @@ public class DefaultModelBuilder } } problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) - .setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg ) - .setException( e ) ); + .setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg ).setException( e ) ); throw problems.newModelBuildingException(); } @@ -621,9 +646,8 @@ public class DefaultModelBuilder catch ( InvalidRepositoryException e ) { problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() ) - .setLocation( repository.getLocation( "" ) ) - .setException( e ) ); + .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() ) + .setLocation( repository.getLocation( "" ) ).setException( e ) ); } } } @@ -675,7 +699,8 @@ public class DefaultModelBuilder if ( versions.get( key ) == null && managedVersions.get( key ) == null ) { InputLocation location = plugins.get( key ).getLocation( "" ); - problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ) + problems + .add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ) .setMessage( "'build.plugins.plugin.version' for " + key + " is missing." ) .setLocation( location ) ); } @@ -800,9 +825,9 @@ public class DefaultModelBuilder if ( !"pom".equals( parentModel.getPackaging() ) ) { problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) - .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel ) + .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel ) + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" ) - .setLocation( parentModel.getLocation( "packaging" ) ) ); + .setLocation( parentModel.getLocation( "packaging" ) ) ); } } else @@ -817,20 +842,52 @@ public class DefaultModelBuilder DefaultModelProblemCollector problems ) throws ModelBuildingException { - ModelSource candidateSource = getParentPomFile( childModel, childSource ); - - if ( candidateSource == null ) + final Parent parent = childModel.getParent(); + final ModelSource candidateSource; + final Model candidateModel; + final WorkspaceModelResolver resolver = request.getWorkspaceModelResolver(); + if ( resolver == null ) { - return null; - } + candidateSource = getParentPomFile( childModel, childSource ); + + if ( candidateSource == null ) + { + return null; + } + + File pomFile = null; + if ( candidateSource instanceof FileModelSource ) + { + pomFile = ( (FileModelSource) candidateSource ).getPomFile(); + } - File pomFile = null; - if ( candidateSource instanceof FileModelSource ) + candidateModel = readModel( candidateSource, pomFile, request, problems ); + } + else { - pomFile = ( (FileModelSource) candidateSource ).getPomFile(); + try + { + 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 ) ); + throw problems.newModelBuildingException(); + } + if ( candidateModel == null ) + { + return null; + } + candidateSource = new FileModelSource( candidateModel.getPomFile() ); } - Model candidateModel = readModel( candidateSource, pomFile, request, problems ); + // + // TODO:jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we + // 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 ) @@ -844,8 +901,6 @@ public class DefaultModelBuilder version = candidateModel.getParent().getVersion(); } - Parent parent = childModel.getParent(); - if ( groupId == null || !groupId.equals( parent.getGroupId() ) || artifactId == null || !artifactId.equals( parent.getArtifactId() ) ) { @@ -861,15 +916,19 @@ public class DefaultModelBuilder problems.setSource( childModel ); problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE ) - .setMessage( buffer.toString() ) - .setLocation( parent.getLocation( "" ) ) ); - return null; - } - if ( version == null || !version.equals( parent.getVersion() ) ) - { + .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ) ); return null; } + // + // Here we just need to know that a version is fine to use but this validation we can do in our workspace + // resolver. + // + + /* + * if ( version == null || !version.equals( parent.getVersion() ) ) { return null; } + */ + ModelData parentData = new ModelData( candidateSource, candidateModel, groupId, artifactId, version ); return parentData; @@ -944,9 +1003,7 @@ public class DefaultModelBuilder } problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) - .setMessage( buffer.toString() ) - .setLocation( parent.getLocation( "" ) ) - .setException( e ) ); + .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) ); throw problems.newModelBuildingException(); } @@ -969,18 +1026,17 @@ public class DefaultModelBuilder { if ( childModel.getVersion() == null ) { - 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 { if ( childModel.getVersion().indexOf( "${" ) > -1 ) { - 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" ) ) ); } } @@ -1013,7 +1069,8 @@ public class DefaultModelBuilder importIds.add( importing ); - ModelResolver modelResolver = request.getModelResolver(); + final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver(); + final ModelResolver modelResolver = request.getModelResolver(); ModelBuildingRequest importRequest = null; @@ -1037,25 +1094,25 @@ public class DefaultModelBuilder 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( "" ) ) ); + .setMessage( "'dependencyManagement.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( "'dependencyManagement.dependencies.dependency.artifactId' for " - + dependency.getManagementKey() + " is missing." ) - .setLocation( dependency.getLocation( "" ) ) ); + .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( "" ) ) ); + .setMessage( "'dependencyManagement.dependencies.dependency.version' for " + + dependency.getManagementKey() + " is missing." ) + .setLocation( dependency.getLocation( "" ) ) ); continue; } @@ -1074,67 +1131,85 @@ public class DefaultModelBuilder continue; } - DependencyManagement importMngt = - getCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT ); + DependencyManagement importMngt = getCache( request.getModelCache(), groupId, artifactId, version, + ModelCacheTag.IMPORT ); if ( importMngt == null ) { - if ( modelResolver == null ) + if ( workspaceResolver == null && modelResolver == null ) { throw new IllegalArgumentException( "no model resolver provided, cannot resolve import POM " + ModelProblemUtils.toId( groupId, artifactId, version ) + " for POM " + ModelProblemUtils.toSourceHint( model ) ); } - ModelSource importSource; - try + Model importModel = null; + if ( workspaceResolver != null ) { - importSource = modelResolver.resolveModel( groupId, artifactId, version ); + 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; + } } - catch ( UnresolvableModelException e ) + + // no workspace resolver or workspace resolver returned null (i.e. model not in workspace) + if ( importModel == null ) { - StringBuilder buffer = new StringBuilder( 256 ); - buffer.append( "Non-resolvable import POM" ); - if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) ) + final ModelSource importSource; + try { - buffer.append( " " ).append( ModelProblemUtils.toId( groupId, artifactId, version ) ); + importSource = modelResolver.resolveModel( groupId, artifactId, version ); } - buffer.append( ": " ).append( e.getMessage() ); + 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( "" ) ) + problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) + .setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) ) .setException( e ) ); - continue; - } + 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() ); - } + 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() ); + importRequest.setModelSource( importSource ); + importRequest.setModelResolver( modelResolver.newCopy() ); - ModelBuildingResult importResult; - try - { - importResult = build( importRequest ); - } - catch ( ModelBuildingException e ) - { - problems.addAll( e.getProblems() ); - continue; - } + final ModelBuildingResult importResult; + try + { + importResult = build( importRequest ); + } + catch ( ModelBuildingException e ) + { + problems.addAll( e.getProblems() ); + continue; + } - problems.addAll( importResult.getProblems() ); + problems.addAll( importResult.getProblems() ); - Model importModel = importResult.getEffectiveModel(); + importModel = importResult.getEffectiveModel(); + } importMngt = importModel.getDependencyManagement(); http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java index bd4211a..8b4a01b 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java @@ -25,8 +25,10 @@ import java.util.Date; import java.util.List; import java.util.Properties; +import org.apache.maven.model.Model; import org.apache.maven.model.Profile; import org.apache.maven.model.resolution.ModelResolver; +import org.apache.maven.model.resolution.WorkspaceModelResolver; /** * Collects settings that control building of effective models. @@ -37,6 +39,8 @@ public class DefaultModelBuildingRequest implements ModelBuildingRequest { + private Model rawModel; + private File pomFile; private ModelSource modelSource; @@ -67,6 +71,8 @@ public class DefaultModelBuildingRequest private ModelCache modelCache; + private WorkspaceModelResolver workspaceResolver; + /** * Creates an empty request. */ @@ -373,4 +379,30 @@ public class DefaultModelBuildingRequest return this; } + @Override + public Model getRawModel() + { + return rawModel; + } + + @Override + public ModelBuildingRequest setRawModel( Model rawModel ) + { + this.rawModel = rawModel; + return this; + } + + @Override + public WorkspaceModelResolver getWorkspaceModelResolver() + { + return workspaceResolver; + } + + @Override + public ModelBuildingRequest setWorkspaceModelResolver( WorkspaceModelResolver workspaceResolver ) + { + this.workspaceResolver = workspaceResolver; + return this; + } + } http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java index 7074689..c5c2cbf 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java @@ -24,8 +24,10 @@ import java.util.Date; import java.util.List; import java.util.Properties; +import org.apache.maven.model.Model; import org.apache.maven.model.Profile; import org.apache.maven.model.resolution.ModelResolver; +import org.apache.maven.model.resolution.WorkspaceModelResolver; /** * A model building request that delegates all methods invocations to another request, meant for easy transformations by @@ -254,4 +256,30 @@ class FilterModelBuildingRequest return this; } -} + @Override + public Model getRawModel() + { + return request.getRawModel(); + } + + @Override + public ModelBuildingRequest setRawModel( Model rawModel ) + { + request.setRawModel( rawModel ); + return this; + } + + @Override + public WorkspaceModelResolver getWorkspaceModelResolver() + { + return request.getWorkspaceModelResolver(); + } + + @Override + public ModelBuildingRequest setWorkspaceModelResolver( WorkspaceModelResolver workspaceResolver ) + { + request.setWorkspaceModelResolver( workspaceResolver ); + return this; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java index c6c75f9..2a49a21 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java @@ -19,6 +19,10 @@ package org.apache.maven.model.building; * under the License. */ +import java.io.File; + +import org.apache.maven.model.Model; + /** * Builds the effective model from a POM. * @@ -51,4 +55,13 @@ public interface ModelBuilder ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result ) throws ModelBuildingException; + /** + * Performs only the part of {@link ModelBuilder#build(ModelBuildingRequest)} that loads the raw model + * + * @param request + * @return + * @throws ModelBuildingException + */ + Result<? extends Model> buildRawModel( File pomFile, int validationLevel, boolean locationTracking ); + } http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java index 2a3a25a..c10274d 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java @@ -24,8 +24,10 @@ import java.util.Date; import java.util.List; import java.util.Properties; +import org.apache.maven.model.Model; import org.apache.maven.model.Profile; import org.apache.maven.model.resolution.ModelResolver; +import org.apache.maven.model.resolution.WorkspaceModelResolver; /** * Collects settings that control the building of effective models. @@ -63,6 +65,20 @@ public interface ModelBuildingRequest int VALIDATION_LEVEL_STRICT = VALIDATION_LEVEL_MAVEN_3_0; /** + * Gets the raw model to build. If not set, model source will be used to load raw model. + * + * @return The raw model to build or {@code null} if not set. + */ + Model getRawModel(); + + /** + * Set raw model. + * + * @param model + */ + ModelBuildingRequest setRawModel( Model rawModel ); + + /** * Gets the source of the POM to process. * * @return The source of the POM or {@code null} if not set. @@ -315,4 +331,8 @@ public interface ModelBuildingRequest */ ModelBuildingRequest setModelCache( ModelCache modelCache ); -} + WorkspaceModelResolver getWorkspaceModelResolver(); + + ModelBuildingRequest setWorkspaceModelResolver( WorkspaceModelResolver workspaceResolver ); + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java new file mode 100644 index 0000000..a962897 --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java @@ -0,0 +1,255 @@ +package org.apache.maven.model.building; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import static com.google.common.base.Predicates.in; +import static com.google.common.collect.Iterables.any; +import static com.google.common.collect.Iterables.concat; +import static com.google.common.collect.Iterables.transform; +import static java.util.Collections.singleton; +import static java.util.EnumSet.of; +import static org.apache.maven.model.building.ModelProblem.Severity.ERROR; +import static org.apache.maven.model.building.ModelProblem.Severity.FATAL; + +import java.util.Arrays; +import java.util.Collections; + +import org.apache.maven.model.building.ModelProblem.Severity; + +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; + +/** + * There are various forms of results that are represented by this class: + * <ol> + * <li>success - in which case only the model field is set + * <li>success with warnings - model field + non-error model problems + * <li>error - no model, but diagnostics + * <li>error - (partial) model and diagnostics + * </ol> + * Could encode these variants as subclasses, but kept in one for now + * + * @author bbusjaeger + * @param <T> + */ +public class Result<T> +{ + + /** + * Success without warnings + * + * @param model + * @return + */ + public static <T> Result<T> success( T model ) + { + return success( model, Collections.<ModelProblem>emptyList() ); + } + + /** + * Success with warnings + * + * @param model + * @param problems + * @return + */ + public static <T> Result<T> success( T model, Iterable<? extends ModelProblem> problems ) + { + assert !hasErrors( problems ); + return new Result<T>( false, model, problems ); + } + + /** + * Success with warnings + * + * @param model + * @param results + * @return + */ + public static <T> Result<T> success( T model, Result<?>... results ) + { + return success( model, Iterables.concat( Iterables.transform( Arrays.asList( results ), GET_PROBLEMS ) ) ); + } + + /** + * Error with problems describing the cause + * + * @param problems + * @return + */ + public static <T> Result<T> error( Iterable<? extends ModelProblem> problems ) + { + return error( null, problems ); + } + + public static <T> Result<T> error( T model ) + { + return error( model, Collections.<ModelProblem>emptyList() ); + } + + public static <T> Result<T> error( Result<?> result ) + { + return error( result.getProblems() ); + } + + public static <T> Result<T> error( Result<?>... results ) + { + return error( Iterables.concat( Iterables.transform( Arrays.asList( results ), GET_PROBLEMS ) ) ); + } + + /** + * Error with partial result and problems describing the cause + * + * @param model + * @param problems + * @return + */ + public static <T> Result<T> error( T model, Iterable<? extends ModelProblem> problems ) + { + return new Result<T>( true, model, problems ); + } + + /** + * New result - determine whether error or success by checking problems for errors + * + * @param model + * @param problems + * @return + */ + public static <T> Result<T> newResult( T model, Iterable<? extends ModelProblem> problems ) + { + return new Result<T>( hasErrors( problems ), model, problems ); + } + + /** + * New result consisting of given result and new problem. Convenience for newResult(result.get(), + * concat(result.getProblems(),problems)). + * + * @param result + * @param problem + * @return + */ + public static <T> Result<T> addProblem( Result<T> result, ModelProblem problem ) + { + return addProblems( result, singleton( problem ) ); + } + + /** + * New result that includes the given + * + * @param result + * @param problems + * @return + */ + public static <T> Result<T> addProblems( Result<T> result, Iterable<? extends ModelProblem> problems ) + { + return new Result<T>( result.hasErrors() || hasErrors( problems ), result.get(), concat( result.getProblems(), + problems ) ); + } + + public static <T> Result<T> addProblems( Result<T> result, Result<?>... results ) + { + return addProblems( result, Iterables.concat( Iterables.transform( Arrays.asList( results ), GET_PROBLEMS ) ) ); + } + + /** + * Turns the given results into a single result by combining problems and models into single collection. + * + * @param results + * @return + */ + public static <T> Result<Iterable<T>> newResultSet( Iterable<? extends Result<? extends T>> results ) + { + final boolean hasErrors = any( transform( results, new Function<Result<?>, Boolean>() + { + @Override + public Boolean apply( Result<?> input ) + { + return input.hasErrors(); + } + } ), Predicates.equalTo( true ) ); + final Iterable<T> models = transform( results, new Function<Result<? extends T>, T>() + { + @Override + public T apply( Result<? extends T> input ) + { + return input.get(); + } + } ); + final Iterable<ModelProblem> problems = concat( transform( results, GET_PROBLEMS ) ); + return new Result<Iterable<T>>( hasErrors, models, problems ); + } + + // helper to determine if problems contain error + private static boolean hasErrors( Iterable<? extends ModelProblem> problems ) + { + return any( transform( problems, new Function<ModelProblem, Severity>() + { + @Override + public Severity apply( ModelProblem input ) + { + return input.getSeverity(); + } + } ), in( of( ERROR, FATAL ) ) ); + } + + /** + * Class definition + */ + + private final boolean errors; + + private final T value; + + private final Iterable<? extends ModelProblem> problems; + + private Result( boolean errors, T model, Iterable<? extends ModelProblem> problems ) + { + this.errors = errors; + this.value = model; + this.problems = problems; + } + + public Iterable<? extends ModelProblem> getProblems() + { + return problems; + } + + public T get() + { + return value; + } + + public boolean hasErrors() + { + return errors; + } + + private static final Function<Result<?>, Iterable<? extends ModelProblem>> GET_PROBLEMS = + new Function<Result<?>, Iterable<? extends ModelProblem>>() + { + @Override + public Iterable<? extends ModelProblem> apply( Result<?> input ) + { + return input.getProblems(); + } + }; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java index 733a276..bdb623a 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java @@ -78,6 +78,22 @@ public class UnresolvableModelException } /** + * Creates a new exception with specified cause + * + * @param cause + * @param groupId + * @param artifactId + * @param version + */ + public UnresolvableModelException( Throwable cause, String groupId, String artifactId, String version ) + { + super( cause ); + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + } + + /** * Gets the group id of the unresolvable model. * * @return The group id of the unresolvable model, can be empty but never {@code null}. http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java ---------------------------------------------------------------------- diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java new file mode 100644 index 0000000..d12edea --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java @@ -0,0 +1,33 @@ +package org.apache.maven.model.resolution; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.model.Model; + +public interface WorkspaceModelResolver +{ + + Model resolveRawModel( String groupId, String artifactId, String versionConstraint ) + throws UnresolvableModelException; + + Model resolveEffectiveModel( String groupId, String artifactId, String versionConstraint ) + throws UnresolvableModelException; + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model/src/main/mdo/maven.mdo ---------------------------------------------------------------------- diff --git a/maven-model/src/main/mdo/maven.mdo b/maven-model/src/main/mdo/maven.mdo index 43bdb7e..2821ea6 100644 --- a/maven-model/src/main/mdo/maven.mdo +++ b/maven-model/src/main/mdo/maven.mdo @@ -1466,12 +1466,18 @@ <version>4.0.0+</version> <code> <![CDATA[ + private String managementKey; + /** * @return the management key as <code>groupId:artifactId:type</code> */ public String getManagementKey() { - return groupId + ":" + artifactId + ":" + type + ( classifier != null ? ":" + classifier : "" ); + if ( managementKey == null ) + { + managementKey = groupId + ":" + artifactId + ":" + type + ( classifier != null ? ":" + classifier : "" ); + } + return managementKey; } ]]> </code>