o getting rid of some dead code in the project builder in preparation for trying to group more of the profile handling code as a test is failing in the embedder related to profiles while everything in the pom construction test is working correctly.

git-svn-id: https://svn.apache.org/repos/asf/maven/components/branches/MNG-2766@775141 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jason van Zyl 2009-05-15 14:08:43 +00:00
parent 49a8b628b3
commit 107b03a1f7
10 changed files with 56 additions and 634 deletions

View File

@ -1,36 +0,0 @@
BOOTSTRAPPING BASICS
-----------------------
You'll need:
- Java 1.5
- Ant 1.6.5 or later
First, give Ant a location into which the completed Maven distro should be installed:
export M2_HOME=$HOME/apps/maven/apache-maven-3.0-SNAPSHOT
Then, run Ant:
ant -f build-mercury.xml
You can use additiona options on ant command line:
-Dmaven.repo.update.policy={never|always|daily}
-Dmaven.repo.system={mercury|legacy}
-Dmaven.home=$HOME/apps/maven/apache-maven-3.0-SNAPSHOT
if you'd like to debug the bootstrap from Eclipse, uncomment the debugging options in the build-mercury.xml around
line 310, then use the following commands:
For the first time - run the following, it will update the local repo
ant -f build-mercury.xml -Dmaven.repo.update.policy=always -Dmaven.repo.system=mercury
then you can run
ant -f build-mercury.xml -Dmaven.repo.update.policy=never -Dmaven.repo.system=mercury
not to bother with repo updates

View File

@ -17,7 +17,6 @@
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -986,6 +985,6 @@ private void downloadProjectDependencies( MavenSession session, String scope )
ArtifactResolutionResult result = repositorySystem.resolve( request ); ArtifactResolutionResult result = repositorySystem.resolve( request );
resolutionErrorHandler.throwErrors( request, result ); resolutionErrorHandler.throwErrors( request, result );
project.setArtifacts( result.getArtifacts() ); project.setArtifacts( result.getArtifacts() );
} }
} }

View File

@ -279,12 +279,12 @@ public MavenProjectBuildingResult buildProjectWithDependencies( File pomFile, Pr
{ {
MavenProject project = build( pomFile, configuration ); MavenProject project = build( pomFile, configuration );
Artifact artifact = Artifact artifact = repositorySystem.createProjectArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion() );
repositorySystem.createProjectArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion() );
artifact.setFile( pomFile ); artifact.setFile( pomFile );
ArtifactResolutionRequest request = new ArtifactResolutionRequest() ArtifactResolutionRequest request = new ArtifactResolutionRequest()
.setArtifact( artifact ) .setArtifact( artifact )
.setResolveRoot( false )
.setResolveTransitively( true ) .setResolveTransitively( true )
.setLocalRepository( configuration.getLocalRepository() ) .setLocalRepository( configuration.getLocalRepository() )
.setRemoteRepostories( project.getRemoteArtifactRepositories() ) .setRemoteRepostories( project.getRemoteArtifactRepositories() )
@ -302,8 +302,6 @@ public MavenProjectBuildingResult buildProjectWithDependencies( File pomFile, Pr
project.setArtifacts( result.getArtifacts() ); project.setArtifacts( result.getArtifacts() );
project.getArtifacts().remove( artifact );
return new MavenProjectBuildingResult( project, result ); return new MavenProjectBuildingResult( project, result );
} }
@ -377,12 +375,8 @@ private DomainModel build( String projectId, File pomFile, ProjectBuilderConfigu
if ( domainModel.getParentId() != null ) if ( domainModel.getParentId() != null )
{ {
List<DomainModel> mavenParents; List<DomainModel> mavenParents;
MavenProject topProject = projectBuilderConfiguration.getTopLevelProjectFromReactor();
if ( useTopLevelProjectForParent( domainModel, topProject ) ) if ( isParentLocal( domainModel.getRelativePathOfParent(), pomFile.getParentFile() ) )
{
mavenParents = getDomainModelParentsFromLocalPath( domainModel, localRepository, remoteRepositories, topProject.getFile(), projectBuilderConfiguration );
}
else if ( isParentLocal( domainModel.getRelativePathOfParent(), pomFile.getParentFile() ) )
{ {
mavenParents = getDomainModelParentsFromLocalPath( domainModel, localRepository, remoteRepositories, pomFile.getParentFile(), projectBuilderConfiguration ); mavenParents = getDomainModelParentsFromLocalPath( domainModel, localRepository, remoteRepositories, pomFile.getParentFile(), projectBuilderConfiguration );
} }
@ -445,19 +439,6 @@ else if ( isParentLocal( domainModel.getRelativePathOfParent(), pomFile.getParen
return transformedDomainModel; return transformedDomainModel;
} }
private static boolean useTopLevelProjectForParent( DomainModel currentModel, MavenProject topProject )
throws IOException
{
if ( topProject == null || currentModel.getModel().getParent() == null )
{
return false;
}
return topProject.getGroupId().equals( currentModel.getParentGroupId() ) && topProject.getArtifactId().equals( currentModel.getParentArtifactId() )
&& topProject.getVersion().equals( currentModel.getParentVersion() );
}
private void validateModel( Model model, File pomFile ) private void validateModel( Model model, File pomFile )
throws InvalidProjectModelException throws InvalidProjectModelException
{ {
@ -604,22 +585,16 @@ private List<DomainModel> getDomainModelParentsFromLocalPath( DomainModel domain
{ {
parentFile = new File( parentFile.getAbsolutePath(), "pom.xml" ); parentFile = new File( parentFile.getAbsolutePath(), "pom.xml" );
} }
MavenProject topProject = projectBuilderConfiguration.getTopLevelProjectFromReactor(); MavenProject topProject = projectBuilderConfiguration.getTopLevelProjectFromReactor();
boolean isTop = useTopLevelProjectForParent( domainModel, topProject );
DomainModel parentDomainModel = null; DomainModel parentDomainModel = null;
if ( !isTop ) if ( !parentFile.isFile() )
{ {
if ( !parentFile.isFile() ) throw new IOException( "File does not exist: File = " + parentFile.getAbsolutePath() );
{
throw new IOException( "File does not exist: File = " + parentFile.getAbsolutePath() );
}
parentDomainModel = new DomainModel( parentFile );
parentDomainModel.setProjectDirectory( parentFile.getParentFile() );
}
else
{
parentDomainModel = new DomainModel( projectBuilderConfiguration.getTopLevelProjectFromReactor().getFile() );
} }
parentDomainModel = new DomainModel( parentFile );
parentDomainModel.setProjectDirectory( parentFile.getParentFile() );
if ( !parentDomainModel.matchesParentOf( domainModel ) ) if ( !parentDomainModel.matchesParentOf( domainModel ) )
{ {
@ -639,20 +614,8 @@ private List<DomainModel> getDomainModelParentsFromLocalPath( DomainModel domain
domainModels.add( parentDomainModel ); domainModels.add( parentDomainModel );
if ( domainModel.getParentId() != null ) if ( domainModel.getParentId() != null )
{ {
if ( isTop ) if ( isParentLocal( parentDomainModel.getRelativePathOfParent(), parentFile.getParentFile() ) )
{
if ( isParentLocal( parentDomainModel.getRelativePathOfParent(), parentFile.getParentFile() ) )
{
domainModels
.addAll( getDomainModelParentsFromLocalPath( parentDomainModel, localRepository, remoteRepositories, topProject.getFile().getParentFile(), projectBuilderConfiguration ) );
}
else
{
domainModels.addAll( getDomainModelParentsFromRepository( parentDomainModel, localRepository, remoteRepositories ) );
}
}
else if ( isParentLocal( parentDomainModel.getRelativePathOfParent(), parentFile.getParentFile() ) )
{ {
domainModels.addAll( getDomainModelParentsFromLocalPath( parentDomainModel, localRepository, remoteRepositories, parentFile.getParentFile(), projectBuilderConfiguration ) ); domainModels.addAll( getDomainModelParentsFromLocalPath( parentDomainModel, localRepository, remoteRepositories, parentFile.getParentFile(), projectBuilderConfiguration ) );
} }

View File

@ -577,12 +577,16 @@ public List<String> getTestClasspathElements()
list.add( getBuild().getOutputDirectory() ); list.add( getBuild().getOutputDirectory() );
System.out.println( ">>>>> " + getArtifacts() );
for ( Artifact a : getArtifacts() ) for ( Artifact a : getArtifacts() )
{ {
if ( a.getArtifactHandler().isAddedToClasspath() ) if ( a.getArtifactHandler().isAddedToClasspath() )
{ {
File file = a.getFile(); File file = a.getFile();
System.out.println( ">> " + a.getArtifactId() );
if ( file == null ) if ( file == null )
{ {
throw new DependencyResolutionRequiredException( a ); throw new DependencyResolutionRequiredException( a );

View File

@ -20,8 +20,6 @@
*/ */
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -29,13 +27,10 @@
import org.apache.maven.artifact.repository.DefaultArtifactRepository; import org.apache.maven.artifact.repository.DefaultArtifactRepository;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.profiles.DefaultProfileManager; import org.apache.maven.profiles.DefaultProfileManager;
import org.apache.maven.profiles.ProfileActivationContext; import org.apache.maven.profiles.ProfileActivationContext;
import org.apache.maven.project.harness.PomTestWrapper; import org.apache.maven.project.harness.PomTestWrapper;
import org.codehaus.plexus.PlexusTestCase; import org.codehaus.plexus.PlexusTestCase;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
public class PomConstructionTest public class PomConstructionTest
extends PlexusTestCase extends PlexusTestCase
@ -50,13 +45,11 @@ public class PomConstructionTest
private File testDirectory; private File testDirectory;
private File testMixinDirectory;
protected void setUp() protected void setUp()
throws Exception throws Exception
{ {
testDirectory = new File( getBasedir(), BASE_POM_DIR ); testDirectory = new File( getBasedir(), BASE_POM_DIR );
testMixinDirectory = new File( getBasedir(), BASE_MIXIN_DIR ); new File( getBasedir(), BASE_MIXIN_DIR );
mavenProjectBuilder = (DefaultMavenProjectBuilder) lookup( MavenProjectBuilder.class ); mavenProjectBuilder = (DefaultMavenProjectBuilder) lookup( MavenProjectBuilder.class );
} }
@ -1470,10 +1463,11 @@ private PomTestWrapper buildPom( String pomPath, Properties executionProperties,
localRepoUrl = "file://" + localRepoUrl; localRepoUrl = "file://" + localRepoUrl;
config.setLocalRepository( new DefaultArtifactRepository( "local", localRepoUrl, new DefaultRepositoryLayout() ) ); config.setLocalRepository( new DefaultArtifactRepository( "local", localRepoUrl, new DefaultRepositoryLayout() ) );
ProfileActivationContext pCtx = new ProfileActivationContext( null, true ); ProfileActivationContext profileActivationContext = new ProfileActivationContext( null, true );
if ( profileIds != null ) if ( profileIds != null )
{ {
pCtx.setExplicitlyActiveProfileIds( Arrays.asList( profileIds ) ); profileActivationContext.setExplicitlyActiveProfileIds( Arrays.asList( profileIds ) );
} }
if ( executionProperties != null ) if ( executionProperties != null )
@ -1481,7 +1475,7 @@ private PomTestWrapper buildPom( String pomPath, Properties executionProperties,
config.setExecutionProperties( executionProperties ); config.setExecutionProperties( executionProperties );
} }
config.setGlobalProfileManager( new DefaultProfileManager( pCtx ) ); config.setGlobalProfileManager( new DefaultProfileManager( profileActivationContext ) );
return new PomTestWrapper( pomFile, mavenProjectBuilder.build( pomFile, config ) ); return new PomTestWrapper( pomFile, mavenProjectBuilder.build( pomFile, config ) );
} }

View File

@ -54,8 +54,7 @@ public static void main( String[] args )
} }
/** @noinspection ConfusingMainMethod */ /** @noinspection ConfusingMainMethod */
public static int main( String[] args, public static int main( String[] args, ClassWorld classWorld )
ClassWorld classWorld )
{ {
MavenCli cli = new MavenCli(); MavenCli cli = new MavenCli();

View File

@ -137,6 +137,30 @@ public void testExecutionUsingABaseDirectory()
assertTrue( jar.exists() ); assertTrue( jar.exists() );
} }
public void testWithOptionalDependencies()
throws Exception
{
File testDirectory = new File( basedir, "src/test/projects/optional-dep" );
File targetDirectory = new File( basedir, "target/projects/option-dep" );
FileUtils.copyDirectoryStructure( testDirectory, targetDirectory );
MavenExecutionRequest request = new DefaultMavenExecutionRequest()
.setBaseDirectory( targetDirectory )
.setShowErrors( true )
.setGoals( Arrays.asList( new String[] { "install" } ) );
MavenExecutionResult result = mavenEmbedder.execute( request );
if (result.hasExceptions() )
{
result.getExceptions().get( 0 ).printStackTrace();
fail( "Project didn't execute correctly.");
}
}
/*MNG-3919*/ /*MNG-3919*/
public void testWithInvalidGoal() public void testWithInvalidGoal()
throws Exception throws Exception
@ -147,8 +171,10 @@ public void testWithInvalidGoal()
FileUtils.copyDirectoryStructure( testDirectory, targetDirectory ); FileUtils.copyDirectoryStructure( testDirectory, targetDirectory );
MavenExecutionRequest request = new DefaultMavenExecutionRequest().setBaseDirectory( targetDirectory ) MavenExecutionRequest request = new DefaultMavenExecutionRequest()
.setShowErrors( true ).setGoals( Arrays.asList( new String[]{"validate"} ) ); .setBaseDirectory( targetDirectory )
.setShowErrors( true )
.setGoals( Arrays.asList( new String[]{"validate"} ) );
MavenExecutionResult result = mavenEmbedder.execute( request ); MavenExecutionResult result = mavenEmbedder.execute( request );
List exceptions = result.getExceptions(); List exceptions = result.getExceptions();
@ -199,7 +225,8 @@ public void testExecutionUsingAProfileWhichSetsAProperty()
// Check with profile not active // Check with profile not active
MavenExecutionRequest requestWithoutProfile = new DefaultMavenExecutionRequest() MavenExecutionRequest requestWithoutProfile = new DefaultMavenExecutionRequest()
.setPom( new File( targetDirectory, "pom.xml" ) ).setShowErrors( true ) .setPom( new File( targetDirectory, "pom.xml" ) )
.setShowErrors( true )
.setGoals( Arrays.asList( new String[] { "validate" } ) ); .setGoals( Arrays.asList( new String[] { "validate" } ) );
MavenExecutionResult r0 = mavenEmbedder.execute( requestWithoutProfile ); MavenExecutionResult r0 = mavenEmbedder.execute( requestWithoutProfile );
@ -226,6 +253,9 @@ public void testExecutionUsingAProfileWhichSetsAProperty()
MavenProject p1 = r1.getProject(); MavenProject p1 = r1.getProject();
System.out.println( p1 );
System.out.println( p1.getProperties() );
assertEquals( "true", p1.getProperties().getProperty( "embedderProfile" ) ); assertEquals( "true", p1.getProperties().getProperty( "embedderProfile" ) );
assertEquals( "jason", p1.getProperties().getProperty( "name" ) ); assertEquals( "jason", p1.getProperties().getProperty( "name" ) );

Binary file not shown.

View File

@ -1,529 +0,0 @@
\documentclass[12pt]{amsart}
\usepackage{geometry}
\geometry{a4paper} % or letter or a5paper or ... etc
% \geometry{landscape} % rotated page geometry
% See the ``Article customise'' template for come common customisations
\title{Maven Project Builder Specification}
\author{Shane Isbell}
\makeglossary
\begin{document}
\maketitle
\tableofcontents
\section{Introduction}
\subsection{Purpose}
The purpose of this document is to cover how the Maven project model is constructed and interpolated. Out of scope are issues such as dependency resolution.
\section{Model Transformations}
\subsection{Canonical Data Format}
Maven supports a canonical data format for the pom that includes 465 model properties (we refer to each ordered pair of uri/values as a model property).
\glossary{doo}
\begin{verbatim}
http://apache.org/maven/project/modelVersion
http://apache.org/maven/project/groupId
http://apache.org/maven/project/artifactId
\end{verbatim}
So a valid set would contain ordered pairs:
\begin{math}
\mathcal{A}= \{\langle "http://apache.org/maven/project/groupId", "org.apache.maven"\rangle,
\langle "http://apache.org/maven/project/artifactId", "mavencore"\}\rangle \ldots\}.
\end{math}
Technically \begin{math}\mathcal{A}\end{math} is also ordered.
Anyone is free to create a transformer from any another format (yaml, .NET projects files, etc) to this canonical data format, giving them all the benefits of project inheritance and interpolation that Maven uses in building a project.
\subsubsection{Collections}
A model property may be specified as a collection, which allows specialized join rules for adding model properties. Collections of collections are allowed.
\begin{verbatim}
http://apache.org/maven/project/build/plugins#collection
http://apache.org/maven/project/build/plugins#collection/plugin/executions#collection
http://apache.org/maven/project/profiles#collection
\end{verbatim}
There are 31 collections within the canonical data format.
\subsubsection{Sets}
A model property may be specified as a set, which means that model properties are not duplicated. Generally sets are only used on configuration properties of the plugins.
\begin{verbatim}
http://...pluginManagement/plugins#collection/plugin/configuration#set
http://...plugins#collection/plugin/configuration#set
\end{verbatim}
\subsubsection{Singletons}
Any model property not defined as a collection or set is a singleton, This means that only one entry containing the model property's URI is allowed in the transformed list.
\section{General Inheritance Rules}
General inheritance rules are those rules applied to a list of model properties, independent of the domain context. The framework delegates domain specific inheritance rules to ModelTransformers provided to it by the invoking application. These will be covered in the next section, under \emph{Maven Project Inheritance Rules}.
\subsection{Constructing}
Basic construction rules are as follows
\begin{enumerate}
\item Let there be a collection of domain models (poms) denoted by set \begin{math}\mathcal{D}_{i}\end{math}, where for some \begin{math} n \in \mathbb{N} \end{math} the collection is ordered from most specific to least specific \begin{math}\mathcal{C} = \{\mathcal{D}_{0}, \mathcal{D}_{1},...,\mathcal{D}_{n} \} \end{math}. \begin{math}\mathcal{D}_{n}\end{math} is the SuperPom and must be contained within \begin{math}\mathcal{C}\end{math}, even if it is the only element.
\item Let \begin{math}p_j\end{math} be an ordered pair (or model property). In the case of the pom, \begin{math}j=nodes + properties\end{math} of the pom. Define t as a function operating on elements of \begin{math}\mathcal{C}\end{math} that transforms each element to a set of model properties. \begin{math}\mathcal{D}'_{i}=t(\mathcal{D}_{i})=\{p_0,p_1,...p_m\}\end{math}. We end up with a transformed collection of domain models: \begin{math}\mathcal{C'} = \{\mathcal{D'}_{0}, \mathcal{D'}_{1},...,\mathcal{D'}_{n} \} \end{math}.
\item Add in mixin containing global setting profiles
\item Next domain specific rules are applied (See section 3). Let tr be a domain transform rule: \begin{math}
\forall_j \forall_i \mathcal{A}_{i,j} \subseteq \mathcal{D'}_{i} \end{math} such that \begin{math} \mathcal{A'}_{i,j} = \{tr(p_0), tr(p_1),...,tr(p_n))\}. \end{math} tr may change either the model property URI or value or may transform the property to a null value (remove it) or it could add additional model properties not from the original set. We are left with \begin{math}
\mathcal{C''} = \forall_j \forall_i \bigcup_{i,j}(\mathcal{D'}_{i} \cup \mathcal{A'}_{i,j} - (\mathcal{D'}_{i} \cap\mathcal{A}_{i,j})) \end{math}. Thus \begin{math}\mathcal{C''} \end{math} is just a set of transformed and untransformed model properties from all of the domain models \begin{math}
\mathcal{D}_{i} \end{math}. These model properties are still ordered from most specialized model to least.
\item Model properties are now sorted (see section 2.2). Collections and sets are left in reverse order.
\item Model container rules are applied for collections and sets. The general sorting in the previous step doesn't know how to handle collections and sets and needs to delegate back to the domain specific model containers (Sections 3.4 and 3.5)
\item Model properties are sorted (see section 2.2) again. This is to maintain the original order of collections.
\item Interpolates the model properties (Section 5)
\item Determine active profile(s)
\item Applies Profiles
\item Interpolates the model properties
\item Applies dependency management rules
\item Applies plugin management rules
\end{enumerate}
The last four steps involve cross-applying elements of the pom into the same pom. Inheritance takes place prior to this type of cross-applying operation. These operations have characteristics very similar to mixins, as they are not complete pom models in themselves.
Profiles may contain properties that are used in interpolating the containing pom. Thus interpolation is also done after cross-applying the profile.
\subsection{Sorting}
Let \begin{math}\mathcal{C''}\end{math} be the original set of model properties and let \begin{math}\mathcal{C'''}\end{math} be the new set, which is initially empty. Now iterate over each element (model property) of \begin{math}\mathcal{C''}\end{math} placing the model property into set \begin{math}\mathcal{C'''}\end{math} according to the following rules:
\begin{enumerate}
\item Let \begin{math}u_{i}\end{math} be the uri from model property \begin{math}\langle uri, value\rangle_{i} \end{math} If \begin{math}u_{i}\end{math} = baseUri, then it is placed first in the list. In the case of Maven, http://apache.org/maven/project is the baseUri and defines the top node name.
\item If \begin{math}u_{i}\end{math} is not within any of the model properties contained within \begin{math}\mathcal{C'''}\end{math} then place the model property into \begin{math}\mathcal{C'''}\end{math}. This rule only allows one singleton into the set: \emph{http://.../project/groupId} and since \begin{math}\mathcal{C''}\end{math} is sorted in order of most specialized to least specialized, only the most specialized pom values will be maintained.
\item If \begin{math}u_{i}\end{math} contains a value of \#collection or \#set but does not end with \#collection or \#set then then place the model property into \begin{math}\mathcal{C'''}\end{math}, at the position of its first (and only) parent. For example,\emph{ http://.../project/build/plugins\#collection }would have been added in the previous step (because it was not contained in \begin{math}\mathcal{C'''}\end{math}) but this step would exclude any additional model properties containing \emph{http://.../project/build/plugins\#collection}. However, all model properties containing uri \emph{http://apache.org/maven/project/build/plugins\#collection/plugin} would be added just below its collection. Only one node of a collection type is maintained but multiple children within that collection are allowed.
\end{enumerate}
\subsection{Model Containers}
In addition to the general inheritance rules, there is also the concept of Model Containers, which allow the framework to delegate to specific model container implementations the decision of whether \#collections and \#sets should be joined, deleted, or have no operation applied. This will be covered more fully in section 3.
\subsection{Mixins and Multiple Inheritance}
Currently, Maven 3.0 supports linearlized inheritance, making mixins and multiple inheritance easy. Support for multiple inheritance would require an additional to the pom, within the parents section.
\begin{verbatim}
<parents>
<parent>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-shared-components</artifactId>
<version>9</version>
</parent>
<parent>
<artifactId>maven</artifactId>
<groupId>org.apache.maven</groupId>
<version>3.0-SNAPSHOT</version>
</parent>
</parents>
\end{verbatim}
In the case above, the child pom's model properties would be first in the set, followed by the model properties of \emph{maven-shared-components}; then \emph{maven} project's model properties and finally by the SuperPom's model properties. So from the framework's perspective there is little difference between multiple inheritance and single inheritance.
Mixins would function the same as multiple/single inheritance:
\begin{verbatim}
<mixins>
<mixin>
<groupId>org.apache.maven</groupId>
<artifactId>dependency-mixin</artifactId>
<version>1</version>
</mixin>
<mixin>
<groupId>org.apache.maven</groupId>
<artifactId>repository-mixin</artifactId>
<version>2</version>
</mixin>
</mixins>
\end{verbatim}
The only difference between a parent project and a mixin is that the mixin is abstract (not a complete model).
\section{Maven Project Inheritance Rules}
These rules outlined in this section are provided in the PomTransformer class. The maven-shared-model framework will delegate to this transformer for the processing of the Maven specific domain model rules.
\subsection{Inheriting Version and Group Ids}
If \emph{project.version} is not specified within the child pom, the child pom will use the \emph{project.parent.version} as its own version. Similarly, if \emph{project.groupId} is not within the child pom, the child pom will use the \emph{project.parent.groupId} as its own \emph{project.groupId}.
\subsection{Inheriting URLs}
\subsection{Properties Excluded From Being Overridden}
If the child project defines any of the properties below, they are not overridden by or joined with elements of the parent pom(s).
\begin{enumerate}
\item project.build.resources
\item project.build.testResoures
\item project.pluginRepositories
\item project.organization
\item project.licenses
\item project.developers
\item project.contributors
\item project.mailingLists
\item project.ciManagement
\item project.issueManagement
\item project.distributionsManagement.repository
\item project.distributionsManagement.snapshotRepository
\item project.distributionsManagement.site
\end{enumerate}
\subsection{Properties Excluded From Inheritance}
A child project does not inherit the following properties from its specified parent project\footnote{Technically, project.version, project.groupId and project.artifactId are not inherited from the parent pom. They do, however, have the values of project.parent.version, project.parent.groupId and project.parent.artifactId implicitly applied from the same pom.}. All other properties are inherited, unless otherwise noted below.
\begin{enumerate}
\item project.parent
\item project.name
\item project.packaging
\item project.profiles
\item project.version
\item project.groupId
\item project.prerequisites
\item project.distributionManagement.relocation
\end{enumerate}
\subsection{Marking Containers as Final (Or Not Inherited)}
A parent project can set an inherited property within the following elements of the pom. This will mark the container as final, thus preventing inheritance:
\begin{enumerate}
\item project.build.plugins.plugin
\item project.build.plugins.plugin.executions.execution
\item project.build.pluginManagement.plugins.plugin
\item project.build.pluginManagement.plugins.plugin.executions.execution
\item project.profiles.profile.build.plugins.plugin
\item project.profiles.profile.build.plugins.plugin.executions.execution
\item project.profiles.profile.build.pluginManagement.plugins.plugin
\item project.profiles.profile.build.pluginManagement.plugins.plugin.executions.execution
\item project.reporting.plugins.plugin
\item project.reporting.plugins.plugin.reportSets.reportSet
\item project.profiles.profile.reporting.plugins.plugin
\item project.profiles.profile.reporting.plugins.plugin.reportSets.reportSet
\end{enumerate}
Some examples demonstrating use within the project model:
\begin{verbatim}
<plugin>
<groupId>org.apache.maven</groupId>
<artifactId>sample</artifactId>
<version>1.0</version>
<inherited>false</inherited>
</plugin>
\end{verbatim}
\begin{verbatim}
<plugin>
<groupId>org.apache.maven</groupId>
<artifactId>sample</artifactId>
<version>1.0</version>
<executions>
<execution>
<inherited>false</inherited>
</execution>
</executions>
</plugin>
\end{verbatim}
\subsection{Artifact Inheritance (Model Container)}
\subsubsection{Defined Nodes}
Within the project there are a number of nodes which contain artifactId, groupId and version. These nodes may be inherited or joined.
\begin{enumerate}
\item project.dependencies.dependency
\item project.build.plugins.plugin
\item project.build.plugins.plugin.dependencies.dependency
\item project.build.plugins.plugin.dependencies.dependency.exclusions.exclusion
\item project.dependencyManagement.dependencies.dependency
\item project.build.pluginManagement.plugins.plugin
\item project.build.pluginManagement.plugins.plugin.dependencies.dependency
\item project.reporting.plugins.plugin
\item project.build.extensions.extension
\end{enumerate}
\subsubsection{Rules}
Let the parent project be \begin{math}\mathcal{A}\end{math} and the child project be \begin{math}\mathcal{B}\end{math} . Let both \begin{math}\alpha_i \subset \mathcal{A}\end{math} and \begin{math}\beta_i \subset \mathcal{B}\end{math} be one of the elements listed above. For example, \begin{math}\alpha_1\end{math} would contain all the elements of a project dependency within the parent project.
Both \begin{math}\alpha_i \subset \mathcal{A}\end{math} and \begin{math}\beta_i \subset \mathcal{A}\end{math}, contain at least the following elements:
\begin{enumerate}
\item project.groupId (required)
\item project.artifactId (required)
\item project.version (default value - null)
\item project.type (default value - jar)
\item project.classifier (default value - null)
\end{enumerate}
(1-3) may be values referencing project.parent.groupId, project.parent.artifactId, project.parent.version, where they are not explicitly defined.
More precisely we have:
\begin{math} \forall_i \forall_j \alpha_i = \{\langle groupId, value_j \rangle_i, \langle artifactId, value_{j+1}\rangle_i, \langle version, value_{j+2}\rangle_i, \ldots\}.\end{math}
Now define the following rules:
\begin{enumerate}
\item
\begin{math} R_1 \equiv
groupId(value)^{\alpha_i} = groupId(value)^{\beta_i} \wedge artifactId(value)^{\alpha_i} = artifactId(value)^{\beta_i} \wedge type(value)^{\alpha_i} = type(value)^{\beta_i} \wedge classifier(value)^{\alpha_i} = classifier(value)^{\beta_i}
\end{math}
\item
\begin{math} R_2 \equiv
version(value)^{\alpha_i} = version(value)^{\beta_i}
\end{math}
\end{enumerate}
The inheritance rules are JOIN, NOP, and DELETE:
\begin{enumerate}
\item
\begin{math}
R_1 \wedge R_2 \Rightarrow \mathcal{B}_{new} = \mathcal{B} \cup \alpha_i - (\alpha_i \cap \beta_i)
\end{math}
\item
\begin{math}
\neg R_1\Rightarrow \mathcal{B}_{new} = \mathcal{B} \cup \alpha_i
\end{math}
\item
\begin{math}
R_1 \wedge \neg R_2 \Rightarrow \mathcal{B}_{new} = \mathcal{B} \end{math}
\end{enumerate}
Note that model container rules are performed after basic sorting and collapsing of the model inheritance. So a NOP operation means that a model container from the parent is left within the model, meaning there is a union of the elements. A delete means that the model container from the parent is removed, leaving the set the same.
\subsubsection{Default Group IDs}
To maintain backwards compatibility, the following elements are assigned a default groupId of \emph{org.apache.maven.plugins}, if the groupId is not specified.
\begin{enumerate}
\item project.build.plugins.plugin
\item project.profiles.profile.build.plugins.plugin
\item project.build.pluginManagement.plugins.plugin
\item project.build.profiles.profile.pluginManagement.plugins.plugin
\item project.reporting.plugins.plugin
\item project.profiles.profile.reporting.plugins.plugin
\end{enumerate}
\subsection{Id Inheritance (Model Container)}
\subsubsection{Defined Nodes}
Within the project there are a number of nodes which contain id. Each of the nodes below is an element of a collection, meaning there may be more than one. The ID is used to determine whether the containers should be joined, rather than just added to the collection..
\begin{enumerate}
\item project.pluginRepositories.pluginRepository
\item project.repositories.repository
\item project.reporting.plugins.plugin.reportSets.reportSet
\item project.profiles.profile
\item project.build.plugins.plugin.executions.execution
\end{enumerate}
\subsubsection{Rules}
If an id exists in both the parent and child pom and the ids are equal, then join the nodes, otherwise inherit the node.
\subsubsection{Plugin Execution ID Rules}
If a Plugin Model Container is joined by ID, the following rules apply:
\begin{enumerate}
\item Can not have two or more execution elements lacking an ID.
\item If default-execution-id is explicitly defined as the execution id, it is treated as not having an id for purposes of the above rule.
\item Project.Build.Plugins.Plugin.Executions.Execution.Goals is always joined on an execution id match. Duplicate goals are removed.
\end{enumerate}
The above rules also apply to joining with a pluginManagement node.
\subsection{Plugin Configuration Inheritance}
Plugin nodes are treated as a set. If a child pom contains the same element as a parent pom, then the parent pom element will not be inherited/joined unless the child element contains a property combine.children="append". In this case, it will treat the element as a collection.
\begin{verbatim}
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<testExcludes combine.children="append">
<testExclude implementation="java.lang.String">
**/PersonThreeTest.java
</testExclude>
</testExcludes>
</configuration>
</plugin>
\end{verbatim}
If the parent pom contains an element that the child pom does not have, the element will be inherited.
\section{Management Rules}
\subsection{Dependency/Plugin Management}
Dependency and plugin management are treated the same, so we will only cover dependency management. Our initial set has already been processed for inheritance and interpolated by the time these rules are applied.
Let \begin{math}\mathcal{A}\end{math} be the set of \emph{project.dependencies.dependency} model containers (model containers are themselves sets of model properties).
Let \begin{math}\mathcal{B}\end{math} be the set of
\emph{project.dependencyManagement.dependencies.dependency }model containers. \begin{math}\mathcal{B}\end{math} is processed such that each dependencyManagement reference within its uris is removed. Thus the uris exactly match those contained within \begin{math}\mathcal{A}\end{math}. Call this transformed set \begin{math} \mathcal{B'}\end{math}.
Now we can apply the same artifact container rules between each \begin{math} \mathcal{B'}_{i} \end{math} and \begin{math} \mathcal{A}_{j}\end{math}. as those defined in section 3.4.
\section{Interpolation Rules}
\subsection{Type of Properties}
There are four types of properties in the following order of precedence: maven properties, system (user) properties, project properties, environment (execution) variables.
\subsubsection{Maven Properties}
There are two maven specific properties that can be used: \$\{basedir\} (or \$\{pom.basedir\} or \$\{project.basedir\}) and \$\{build.timestamp\}. \emph{basedir} denotes the project directory of the executing pom, while\emph{ build.timestamp} denotes the time that the build started.
\begin{verbatim}
<build>
<directory>${project.basedir}/target</directory>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
</build>
\end{verbatim}
\subsubsection{System Properties}
These properties are defined on the command line through -D option. For instance, \emph{-DjunitVersion=3.8}. These property values take precedence over project and environment properties and will override them.
\subsubsection{Project Properties} These properties are derived directly from the pom itself: \$\{project.version\}, \$\{project.artifactId\}... So in the code snippet below, \emph{project.build.finalname} will be resolved to\emph{ maven-3.0-SNAPSHOT}.
Note \emph{pom} is an alias for\emph{ project}, so you can also reference the properties through \$\{pom.version\}, \$\{pom.artifactId\}... , although \emph{project} is preferred.
These types of properties also include special rules for the \emph{project.properties }section of the pom. The elements under the properties section can directly be referenced, by name, from within other elements of the pom. For example, the \emph{project.properties }section defines \emph{junitVersion}, allowing the
\emph{ project.build.dependencies.dependency.version} to reference the value by inserting \$\{junitVersion\}
\begin{verbatim}
<project>
<groupId>org.apache.maven</groupId>
<artifactId>maven</artifactId>
<version>3.0-SNAPSHOT</version>
<build>
<finalName>${project.artifactId}-${project.version}</finalName>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junitVersion}</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<junitVersion>3.8.1</junitVersion>
</properties>
</project>
\end{verbatim}
Keep in mind that if you set \emph{-DjunitVersion=3.8} on the command line, then this value would be used for interpolation, not the pom specified one.
\subsubsection{Environment Properties}
The properties are taken from the environment and hold the lowest level of precedence.
\subsection{Processing Rules}
The pom XML is flattened to a list of model properties (this is part of the inheritance processing). The interpolator property list will be referred to as interpolator properties.
\subsubsection{Preprocessing}
The initial interpolator property list is constructed and sorted in order of maven properties, system properties, project properties and environment properties. Being a list, it contains duplicate property keys that may reference different values. A common example occurs when overriding a pom property through the command line -D. So all lower duplicate key values are eliminated, resulting in a set of interpolator properties, where order does not matter.
The maven property \$\{project.basedir\} is only added to the initial list if the pom being interpolated is within the build (not a dependency within the repository).
\subsubsection{Pass 1 -withhold using build directories as interpolator properties} In this pass, the list is preprocessed into a set, but excludes any of the build directories from the interpolator list. In other words, the build directories can be interpolated but they can't be used to interpolate other properties. Interpolating is simply the iteration of all interpolator properties over model properties.
\subsubsection{Pass 2 - set absolute paths on build directories} At this point, the build directories are completely interpolated but they may or may not contain absolute paths. So each build model property is checked and if it contains a relative path, the absolute path is set based on the \$\{project.basedir\} location.
\subsubsection{Pass 3- use build directories as interpolator properties} In this pass, all model properties that contain a build directory reference are interpolated with the build directory interpolator properties, which were withheld from pass 1. Now all directory paths within the pom contain absolute references.
\subsection{Interpolation and Profiles}
Active profiles are applied prior to interpolation so that any \emph{project.profiles.profile.properties} defined within an active profile can be used as an interpolation property [Still to be implemented]
\section{Profiles}
Profiles allow the developer to conditionally add project information to the project model. Each profile has an activation property, with an associated matcher.
We have the following five matchers:
\begin{enumerate}
\item Default - allows to specify a profile that will be active (provided no other profiles are matched)
\item File - allows matching of profile based on the existence or nonexistence of a file
\item JDK - allows matching profile based on JDK
\item Operating System - allows matching profile based on operating system
\item Property - allows matching profile based a user or environmental variable
\end{enumerate}
\subsection{Default Profile Matcher}
Occurs if
project/profiles/profile/activation/activeByDefault
exists in the profile. If no other profiles are matched this one will be used.
\subsection{File}
This matcher will check for the existence (or nonexistence) of files. If
\begin{itemize}
\item project/profiles/profile/activation/file/missing does not exist or
\item project/profiles/profile/activation/file/exists,
\end{itemize}
the profile will activate.
\subsection{JDK}
This matcher will check if project/profiles/profile/activation/jdk value matches the current JDK version in use for the build.
\section{Model Container Operations}
\subsection{Definitions}
\begin{description}
\item[Mode Container Rule] Rule that determines whether the model properties between sets \begin{math} \mathcal{A}\end{math} and \begin{math} \mathcal{B}\end{math} match.
\item[M-Operator] Model Container Operator - an operation on Rules. The result of the M-Operator is a set operation. Each resulting set of an M-Operator has to be equal to the resulting set of another M-Operator defined within the system.
\end{description}
\subsection{M-Operators}
\subsubsection{Definitions}
The Maven system defines the following operators:
\begin{description}
\item[JOIN] M($\mathnormal{\mathcal{R}_{1},\mathcal{R}_{2} ) = \gamma - (\alpha_i \cap \beta_i)}$
\item[NOP] M($\mathnormal{\neg \mathcal{R}_{1}, \mathcal{R}_{2}) = \gamma} $
\item[DELETE] M($\mathnormal{\mathcal{R}_{1}, \neg \mathcal{R}_{2}) = \gamma -\alpha_i} $
\end{description}
Note that $\mathnormal{\gamma=\mathcal{B}\cup \alpha_i}$. This is the set that results after basic sorting and inheritance have been applied to the models.
There are some interesting properties of the above definitions. For example, a JOIN is equivalent to a NOP when the intersection of the model containers is null, or a JOIN is equivalent to a DELETE if there is no child model container.
Also these definitions allow us to clearly see how to undo an operation. For example, say we did a DELETE and now we want to revert the operation. We merely need to add back in the properties of the parent model container, giving us a NOP. To revert a JOIN, we add back in the intersection of the parent and child model containers.
\subsubsection{Negation}
Define negation on the operators as:
\begin{enumerate}
\item $\mathnormal{\neg M(\mathcal{R}_{1},\mathcal{R}_{2} ) =M(\mathcal{R}_{1},\neg \mathcal{R}_{2} ) }$
\item $\mathnormal{\neg M(\neg \mathcal{R}_{1},\mathcal{R}_{2} ) =M(\neg \mathcal{R}_{1}, \mathcal{R}_{2} ) }$
\item $\mathnormal{\neg M(\mathcal{R}_{1}, \neg \mathcal{R}_{2}) = M(\mathcal{R}_{1},\mathcal{R}_{2} )} $
\end{enumerate}
Negation of a JOIN is a DELETE, negation of a NOP is a NOP, negation of a DELETE is a JOIN. To understand the mechanics of negation, we need to look at the underlying set operations.
Take (3), where we negate a DELETE. Since we have defined a negation of a DELETE as a JOIN, the set operations for a negation would be to add in elements of the parent model container and then to remove the intersection of the child and parent model containers.
\subsubsection{Addition}
Define addition operators as:
\begin{description}
\item[Sum of JOINs] $\mathnormal{\sum_{i=1}^n \sum_{j=1}^m M(\mathcal{R}^{\alpha_{i} , \beta_{j}}_{1},\mathcal{R}^{\alpha_{i} , \beta_{j}}_{2} ) }$
\item[Sum of NOPs] $\mathnormal{\sum_{i=1}^n \sum_{j=1}^m M(\neg \mathcal{R}^{\alpha_{i} , \beta_{j}}_{1},\mathcal{R}^{\alpha_{i} , \beta_{j}}_{2} ) }$
\item[Sum of DELETEs] $\mathnormal{\sum_{i=1}^n \sum_{j=1}^m M(\mathcal{R}^{\alpha_{i} , \beta_{j}}_{1},\neg \mathcal{R}^{\alpha_{i} , \beta_{j}}_{2} ) }$
\end{description}
Take the case of Sum of Joins. Let i = 1, meaning there is only one parent model container. Then we have:
\begin{eqnarray}
\sum_{i=1}^n \sum_{j=1}^m M(\mathcal{R}^{\alpha_{i} , \beta_{j}}_{1},\mathcal{R}^{\alpha_{i} , \beta_{j}}_{2} ) & = &
\sum_{j=1}^m M(\mathcal{R}^{\alpha_{1} , \beta_{j}}_{1},\mathcal{R}^{\alpha_{1} , \beta_{j}}_{2} ) \\
& = &
\mathcal{B} \cup \alpha_{1}-(\alpha_{1} \cap \beta_{1}) - (\alpha_{1} \cap \beta_{2}) - \cdots - (\alpha_{1} \cap \beta_{m}) \\ & = &
\mathcal{B} \cup \alpha_{1}-(\alpha_{1} \cap (\beta_{1} \cup \beta_{2} \cup \cdots \cup \beta_{m})
\end{eqnarray}
So we simplify the operation to just adding the parent model container to the child model, and then removing the intersection between that parent model container and the union of all child model container. Thus we can simply the calculation for multiple joins, allowing more efficient processing on the underlying data model.
\appendix
\section{Definitions}
\begin{description}
\item[Collection] Any model property with a URI ending in \#collection
\item[Canonical Data Format] A set of model properties including all possible elements of the Maven model
\item[Delete] Delete Model Container Action. Processing this rule on a model container will delete it's model properties from a model data source.
\item[Element] A model property
\item[Interpolation]
\item[Join] Join Model Container Action. Processing this rule on a model container will join it's model properties with another container's model properties.
\item[Mixin] An abstract model which needn't contain all the required elements of the model.
\item[Model Container] A container for a set of Model Properties associated with a specific URI.
\item[Model Container Action] One of the following actions: delete, join, nop that may be performed on a Model Container.
\item[Model Data Source] A class that provides operations for deleting, joining and querying Model Containers.
\item[Model Property] A property of the model that consists of a URI and a value, which may be null.
\item[Model Transformer] A class that is responsible for transforming from a model format to the
canonical data model. It can also optionally perform various domain specific rules and processing.
\item[Node] A model container
\item[NOP] No operation Model Container Action. Processing this rule on a model container will leave the model properties of the model container untouched.
\item[Profile] - Project information added the project model based on a Profile ActivationProperty
\item[Profile Activation Property] - Property that a developer can specify that triggers the applying of a profile to it's containing project model.
\item[Set] Any model property with a URI ending in \#set
\end{description}
\end{document}

View File

@ -1,2 +0,0 @@
Mirrors defined in settings:
Mirror lookup should always use first declaration, regardless whether exact id match or wildcard match