mirror of https://github.com/apache/maven.git
o Re-introduced 2.x like inheritance assembler and profile injector components which mostly delegate to a common model merger class. First of all, the merger only deals with two models at a time, simplifying its logic compared to the current processors, hopefully allowing us to quickly/easily fix the outstanding POM tests. The ultimate goal is to generate the basic ModelMerger automatically with a new Modello plugin which could be programatically customized via a sub class like MavenModelMerger. It will be interesting to find out how much of the merging rules could be generalized via declarative options in the model. This could allow for generated documentation about how inheritance and profile injection alter the model. Last but not least, generating the merger from the MDO would ease addition of new model elements as these would automatically be considered for inheritance and profile injection.
git-svn-id: https://svn.apache.org/repos/asf/maven/components/branches/MNG-2766@772827 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6b9ddf7bec
commit
51c1cb584c
|
@ -1317,7 +1317,7 @@ public class PomConstructionTest
|
|||
throws Exception
|
||||
{
|
||||
PomTestWrapper pom = buildPom( "boolean-interpolation" );
|
||||
assertTrue ((Boolean) pom.getValue( "repositories[2]/releases/enabled" ) );
|
||||
assertTrue ((Boolean) pom.getValue( "repositories[1]/releases/enabled" ) );
|
||||
assertTrue((Boolean) pom.getValue( "build/resources[1]/filtering" ) );
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,9 @@ import java.util.Arrays;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.maven.model.inheritance.DefaultInheritanceAssembler;
|
||||
import org.apache.maven.model.inheritance.InheritanceAssembler;
|
||||
import org.apache.maven.model.processors.BuildProcessor;
|
||||
import org.apache.maven.model.processors.CiManagementProcessor;
|
||||
import org.apache.maven.model.processors.ContributorsProcessor;
|
||||
|
@ -49,8 +50,15 @@ import org.apache.maven.model.processors.PropertiesProcessor;
|
|||
import org.apache.maven.model.processors.ReportingProcessor;
|
||||
import org.apache.maven.model.processors.RepositoriesProcessor;
|
||||
import org.apache.maven.model.processors.ScmProcessor;
|
||||
import org.apache.maven.model.profile.DefaultProfileInjector;
|
||||
import org.apache.maven.model.profile.ProfileInjector;
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
|
||||
/*
|
||||
* TODO: Get rid of this class and go back to an inheritance assembler, profile injector and default injector, all
|
||||
* orchestrated by the model builder. The processors will also by replaced by the merger.
|
||||
*/
|
||||
|
||||
public class ProcessorContext
|
||||
{
|
||||
|
||||
|
@ -70,7 +78,7 @@ public class ProcessorContext
|
|||
{
|
||||
if(domainModel.isMostSpecialized())
|
||||
{
|
||||
child = (DomainModel) domainModel;
|
||||
child = domainModel;
|
||||
}
|
||||
}
|
||||
if(child == null)
|
||||
|
@ -100,7 +108,9 @@ public class ProcessorContext
|
|||
|
||||
return domainModel;
|
||||
}
|
||||
|
||||
|
||||
private static ProfileInjector profileInjector = new DefaultProfileInjector();
|
||||
|
||||
public static DomainModel mergeProfilesIntoModel(Collection<Profile> profiles, DomainModel domainModel) throws IOException
|
||||
{
|
||||
List<Model> profileModels = new ArrayList<Model>();
|
||||
|
@ -118,8 +128,18 @@ public class ProcessorContext
|
|||
}
|
||||
}
|
||||
profileModels.addAll(externalProfileModels);//external takes precedence
|
||||
|
||||
|
||||
Model model = domainModel.getModel();
|
||||
|
||||
for ( Profile profile : profiles )
|
||||
{
|
||||
profileInjector.injectProfile( model, profile );
|
||||
}
|
||||
if ( true )
|
||||
{
|
||||
return domainModel;
|
||||
}
|
||||
|
||||
profileModels.add( 0, model );
|
||||
List<Processor> processors =
|
||||
Arrays.<Processor> asList( new BuildProcessor( new ArrayList<Processor>() ), new ProfilesModuleProcessor(),
|
||||
|
@ -211,12 +231,25 @@ public class ProcessorContext
|
|||
|
||||
return models;
|
||||
}
|
||||
|
||||
|
||||
private static InheritanceAssembler inheritanceAssembler = new DefaultInheritanceAssembler();
|
||||
|
||||
private static Model processModelsForInheritance(List<Model> models, List<Processor> processors, boolean isProfile)
|
||||
{
|
||||
ModelProcessor modelProcessor = new ModelProcessor( processors, isProfile );
|
||||
Collections.reverse( models );
|
||||
|
||||
Model previousModel = null;
|
||||
for ( Model currentModel : models )
|
||||
{
|
||||
inheritanceAssembler.assembleModelInheritance( currentModel, previousModel, "" );
|
||||
previousModel = currentModel;
|
||||
}
|
||||
if ( true )
|
||||
{
|
||||
return previousModel;
|
||||
}
|
||||
|
||||
int length = models.size();
|
||||
Model target = new Model();
|
||||
if(length == 1)
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package org.apache.maven.model.inheritance;
|
||||
|
||||
/*
|
||||
* 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.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.merge.MavenModelMerger;
|
||||
import org.codehaus.plexus.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* Handles inheritance of model values.
|
||||
*
|
||||
* @author Benjamin Bentmann
|
||||
*/
|
||||
@Component( role = InheritanceAssembler.class )
|
||||
public class DefaultInheritanceAssembler
|
||||
implements InheritanceAssembler
|
||||
{
|
||||
|
||||
private MavenModelMerger merger = new MavenModelMerger();
|
||||
|
||||
public void assembleModelInheritance( Model child, Model parent, String childPathAdjustment )
|
||||
{
|
||||
Map<Object, Object> hints = new HashMap<Object, Object>();
|
||||
hints.put( MavenModelMerger.CHILD_PATH_ADJUSTMENT, childPathAdjustment );
|
||||
merger.merge( child, parent, false, hints );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.apache.maven.model.inheritance;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Handles inheritance of model values.
|
||||
*
|
||||
* @author Benjamin Bentmann
|
||||
*/
|
||||
public interface InheritanceAssembler
|
||||
{
|
||||
|
||||
/**
|
||||
* Merges values from the specified parent model into the given child model.
|
||||
*
|
||||
* @param child The child model into which to merge the values inherited from the parent, must not be
|
||||
* <code>null</code>.
|
||||
* @param parent The (read-only) parent model from which to inherit the values, may be <code>null</code>.
|
||||
* @param childPathAdjustment The relative path adjustment required to navigate from the parent's base directory to
|
||||
* the parent directory of the child's base directory, must not be <code>null</code>.
|
||||
*/
|
||||
void assembleModelInheritance( Model child, Model parent, String childPathAdjustment );
|
||||
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
package org.apache.maven.model.merge;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.apache.maven.model.Dependency;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.ModelBase;
|
||||
import org.apache.maven.model.Plugin;
|
||||
import org.apache.maven.model.PluginExecution;
|
||||
import org.apache.maven.model.Repository;
|
||||
import org.apache.maven.model.RepositoryBase;
|
||||
import org.apache.maven.model.Site;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The domain-specific model merger for the Maven POM..
|
||||
*
|
||||
* @author Benjamin Bentmann
|
||||
*/
|
||||
public class MavenModelMerger
|
||||
extends ModelMerger
|
||||
{
|
||||
|
||||
/**
|
||||
* The hint key for the child path adjustment used during inheritance for URL calculations.
|
||||
*/
|
||||
public static final String CHILD_PATH_ADJUSTMENT = "child-path-adjustment";
|
||||
|
||||
/**
|
||||
* The context key for the artifact id of the target model.
|
||||
*/
|
||||
private static final String ARTIFACT_ID = "artifact-id";
|
||||
|
||||
@Override
|
||||
protected void mergeModel( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
|
||||
{
|
||||
context.put( ARTIFACT_ID, target.getArtifactId() );
|
||||
|
||||
super.mergeModel( target, source, sourceDominant, context );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mergeModelBase_Modules( ModelBase target, ModelBase source, boolean sourceDominant,
|
||||
Map<Object, Object> context )
|
||||
{
|
||||
List<String> src = source.getModules();
|
||||
if ( !src.isEmpty() && sourceDominant )
|
||||
{
|
||||
List<String> tgt = target.getModules();
|
||||
Set<String> merged = new LinkedHashSet<String>( ( tgt.size() + src.size() ) * 2 );
|
||||
merged.addAll( tgt );
|
||||
merged.addAll( src );
|
||||
target.setModules( new ArrayList<String>( merged ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: The order of the merged list could be controlled by an attribute in the model association: target-first,
|
||||
* source-first, dominant-first, recessive-first
|
||||
*/
|
||||
@Override
|
||||
protected void mergeModelBase_Repositories( ModelBase target, ModelBase source, boolean sourceDominant,
|
||||
Map<Object, Object> context )
|
||||
{
|
||||
List<Repository> src = source.getRepositories();
|
||||
if ( !src.isEmpty() )
|
||||
{
|
||||
List<Repository> tgt = target.getRepositories();
|
||||
Map<Object, Repository> merged = new LinkedHashMap<Object, Repository>( ( src.size() + tgt.size() ) * 2 );
|
||||
|
||||
List<Repository> dominant, recessive;
|
||||
if ( sourceDominant )
|
||||
{
|
||||
dominant = src;
|
||||
recessive = tgt;
|
||||
}
|
||||
else
|
||||
{
|
||||
dominant = tgt;
|
||||
recessive = src;
|
||||
}
|
||||
|
||||
for ( Iterator<Repository> it = dominant.iterator(); it.hasNext(); )
|
||||
{
|
||||
Repository element = it.next();
|
||||
Object key = getRepositoryKey( element );
|
||||
merged.put( key, element );
|
||||
}
|
||||
|
||||
for ( Iterator<Repository> it = recessive.iterator(); it.hasNext(); )
|
||||
{
|
||||
Repository element = it.next();
|
||||
Object key = getRepositoryKey( element );
|
||||
if ( !merged.containsKey( key ) )
|
||||
{
|
||||
merged.put( key, element );
|
||||
}
|
||||
}
|
||||
|
||||
target.setRepositories( new ArrayList<Repository>( merged.values() ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mergeSite_Url( Site target, Site source, boolean sourceDominant, Map<Object, Object> context )
|
||||
{
|
||||
String src = source.getUrl();
|
||||
if ( src != null )
|
||||
{
|
||||
if ( sourceDominant )
|
||||
{
|
||||
target.setUrl( src );
|
||||
}
|
||||
else if ( target.getUrl() == null )
|
||||
{
|
||||
target.setUrl( appendPath( src, context.get( ARTIFACT_ID ).toString(),
|
||||
context.get( CHILD_PATH_ADJUSTMENT ).toString() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getDependencyKey( Dependency dependency )
|
||||
{
|
||||
return dependency.getManagementKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getPluginKey( Plugin object )
|
||||
{
|
||||
return object.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getPluginExecutionKey( PluginExecution object )
|
||||
{
|
||||
return object.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getRepositoryBaseKey( RepositoryBase object )
|
||||
{
|
||||
return object.getId();
|
||||
}
|
||||
|
||||
private String appendPath( String parentPath, String childPath, String pathAdjustment )
|
||||
{
|
||||
String uncleanPath = parentPath;
|
||||
|
||||
if ( pathAdjustment != null )
|
||||
{
|
||||
uncleanPath += "/" + pathAdjustment;
|
||||
}
|
||||
|
||||
if ( childPath != null )
|
||||
{
|
||||
uncleanPath += "/" + childPath;
|
||||
}
|
||||
|
||||
String cleanedPath = "";
|
||||
|
||||
int protocolIdx = uncleanPath.indexOf( "://" );
|
||||
|
||||
if ( protocolIdx > -1 )
|
||||
{
|
||||
cleanedPath = uncleanPath.substring( 0, protocolIdx + 3 );
|
||||
uncleanPath = uncleanPath.substring( protocolIdx + 3 );
|
||||
}
|
||||
|
||||
if ( uncleanPath.startsWith( "//" ) )
|
||||
{
|
||||
// preserve leading double slash for UNC paths like "file:////host/pom.xml"
|
||||
cleanedPath += "//";
|
||||
}
|
||||
else if ( uncleanPath.startsWith( "/" ) )
|
||||
{
|
||||
cleanedPath += "/";
|
||||
}
|
||||
|
||||
return cleanedPath + resolvePath( uncleanPath );
|
||||
}
|
||||
|
||||
private String resolvePath( String uncleanPath )
|
||||
{
|
||||
LinkedList<String> pathElements = new LinkedList<String>();
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer( uncleanPath, "/" );
|
||||
|
||||
while ( tokenizer.hasMoreTokens() )
|
||||
{
|
||||
String token = tokenizer.nextToken();
|
||||
|
||||
if ( token.equals( "" ) )
|
||||
{
|
||||
// Empty path entry ("...//.."), remove.
|
||||
}
|
||||
else if ( token.equals( ".." ) )
|
||||
{
|
||||
if ( !pathElements.isEmpty() )
|
||||
{
|
||||
pathElements.removeLast();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pathElements.addLast( token );
|
||||
}
|
||||
}
|
||||
|
||||
StringBuffer cleanedPath = new StringBuffer();
|
||||
|
||||
while ( !pathElements.isEmpty() )
|
||||
{
|
||||
cleanedPath.append( pathElements.removeFirst() );
|
||||
if ( !pathElements.isEmpty() )
|
||||
{
|
||||
cleanedPath.append( '/' );
|
||||
}
|
||||
}
|
||||
|
||||
return cleanedPath.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package org.apache.maven.model.profile;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.maven.model.Build;
|
||||
import org.apache.maven.model.BuildBase;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.ModelBase;
|
||||
import org.apache.maven.model.Profile;
|
||||
import org.apache.maven.model.merge.MavenModelMerger;
|
||||
import org.codehaus.plexus.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* Handles profile injection into the model.
|
||||
*
|
||||
* @author Benjamin Bentmann
|
||||
*/
|
||||
@Component( role = ProfileInjector.class )
|
||||
public class DefaultProfileInjector
|
||||
implements ProfileInjector
|
||||
{
|
||||
|
||||
private ProfileModelMerger merger = new ProfileModelMerger();
|
||||
|
||||
public void injectProfile( Model model, Profile profile )
|
||||
{
|
||||
if ( profile == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( profile != null )
|
||||
{
|
||||
merger.mergeModelBase( model, profile );
|
||||
|
||||
if ( profile.getBuild() != null )
|
||||
{
|
||||
if ( model.getBuild() == null )
|
||||
{
|
||||
model.setBuild( new Build() );
|
||||
}
|
||||
merger.mergeBuildBase( model.getBuild(), profile.getBuild() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ProfileModelMerger
|
||||
extends MavenModelMerger
|
||||
{
|
||||
|
||||
public void mergeModelBase( ModelBase target, ModelBase source )
|
||||
{
|
||||
mergeModelBase( target, source, true, Collections.emptyMap() );
|
||||
}
|
||||
|
||||
public void mergeBuildBase( BuildBase target, BuildBase source )
|
||||
{
|
||||
mergeBuildBase( target, source, true, Collections.emptyMap() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package org.apache.maven.model.profile;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
import org.apache.maven.model.Profile;
|
||||
|
||||
/**
|
||||
* Handles profile injection into the model.
|
||||
*
|
||||
* @author Benjamin Bentmann
|
||||
*/
|
||||
public interface ProfileInjector
|
||||
{
|
||||
|
||||
/**
|
||||
* Merges values from the specified profile into the given model.
|
||||
*
|
||||
* @param model The model into which to merge the values defined by the profile, must not be <code>null</code>.
|
||||
* @param profile The (read-only) profile from whose values should be injected, may be <code>null</code>.
|
||||
*/
|
||||
void injectProfile( Model model, Profile profile );
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue