[MNG-5878] added project.directory property to support module name !=

artifactId in every calculated URLs
This commit is contained in:
Hervé Boutemy 2015-12-05 23:44:20 +01:00
parent 1cb2e92b5a
commit 9b763cc002
7 changed files with 270 additions and 31 deletions

View File

@ -19,14 +19,16 @@ package org.apache.maven.model.inheritance;
* under the License.
*/
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.maven.model.InputLocation;
import org.apache.maven.model.Model;
import org.apache.maven.model.ModelBase;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginContainer;
import org.apache.maven.model.ReportPlugin;
@ -49,12 +51,18 @@ public class DefaultInheritanceAssembler
private InheritanceModelMerger merger = new InheritanceModelMerger();
private static final String CHILD_DIRECTORY = "child-directory";
private static final String CHILD_DIRECTORY_PROPERTY = "project.directory";
@Override
public void assembleModelInheritance( Model child, Model parent, ModelBuildingRequest request,
ModelProblemCollector problems )
{
Map<Object, Object> hints = new HashMap<>();
hints.put( MavenModelMerger.CHILD_PATH_ADJUSTMENT, getChildPathAdjustment( child, parent ) );
String childPath = child.getProperties().getProperty( CHILD_DIRECTORY_PROPERTY, child.getArtifactId() );
hints.put( CHILD_DIRECTORY, childPath );
hints.put( MavenModelMerger.CHILD_PATH_ADJUSTMENT, getChildPathAdjustment( child, parent, childPath ) );
merger.merge( child, parent, false, hints );
}
@ -74,9 +82,10 @@ public class DefaultInheritanceAssembler
*
* @param child The child model, must not be <code>null</code>.
* @param parent The parent model, may be <code>null</code>.
* @param childDirectory The directory defined in child model, may be <code>null</code>.
* @return The path adjustment, can be empty but never <code>null</code>.
*/
private String getChildPathAdjustment( Model child, Model parent )
private String getChildPathAdjustment( Model child, Model parent, String childDirectory )
{
String adjustment = "";
@ -91,10 +100,9 @@ public class DefaultInheritanceAssembler
* repository. In other words, modules where artifactId != moduleDirName will see different effective URLs
* depending on how the model was constructed (from filesystem or from repository).
*/
File childDirectory = child.getProjectDirectory();
if ( childDirectory != null )
if ( child.getProjectDirectory() != null )
{
childName = childDirectory.getName();
childName = child.getProjectDirectory().getName();
}
for ( String module : parent.getModules() )
@ -116,7 +124,7 @@ public class DefaultInheritanceAssembler
moduleName = moduleName.substring( lastSlash + 1 );
if ( moduleName.equals( childName ) && lastSlash >= 0 )
if ( ( moduleName.equals( childName ) || ( moduleName.equals( childDirectory ) ) ) && lastSlash >= 0 )
{
adjustment = module.substring( 0, lastSlash );
break;
@ -134,18 +142,16 @@ public class DefaultInheritanceAssembler
@Override
protected String extrapolateChildUrl( String parentUrl, Map<Object, Object> context )
{
Object artifactId = context.get( ARTIFACT_ID );
Object childDirectory = context.get( CHILD_DIRECTORY );
Object childPathAdjustment = context.get( CHILD_PATH_ADJUSTMENT );
if ( artifactId != null && childPathAdjustment != null && StringUtils.isNotBlank( parentUrl ) )
{
// append childPathAdjustment and artifactId to parent url
return appendPath( parentUrl, artifactId.toString(), childPathAdjustment.toString() );
}
else
if ( StringUtils.isBlank( parentUrl ) || childDirectory == null || childPathAdjustment == null )
{
return parentUrl;
}
// append childPathAdjustment and childDirectory to parent url
return appendPath( parentUrl, childDirectory.toString(), childPathAdjustment.toString() );
}
private String appendPath( String parentUrl, String childPath, String pathAdjustment )
@ -191,6 +197,38 @@ public class DefaultInheritanceAssembler
}
}
@Override
protected void mergeModelBase_Properties( ModelBase target, ModelBase source, boolean sourceDominant,
Map<Object, Object> context )
{
Properties merged = new Properties();
if ( sourceDominant )
{
merged.putAll( target.getProperties() );
putAll( merged, source.getProperties(), CHILD_DIRECTORY_PROPERTY );
}
else
{
putAll( merged, source.getProperties(), CHILD_DIRECTORY_PROPERTY );
merged.putAll( target.getProperties() );
}
target.setProperties( merged );
target.setLocation( "properties",
InputLocation.merge( target.getLocation( "properties" ),
source.getLocation( "properties" ), sourceDominant ) );
}
private void putAll( Map<Object, Object> s, Map<Object, Object> t, Object excludeKey )
{
for ( Map.Entry<Object, Object> e : t.entrySet() )
{
if ( !e.getKey().equals( excludeKey ) )
{
s.put( e.getKey(), e.getValue() );
}
}
}
@Override
protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source,
boolean sourceDominant, Map<Object, Object> context )

View File

@ -57,14 +57,15 @@ Maven Model Builder
** parent resolution until {{{./super-pom.html}super-pom}}
** inheritance assembly: <<<InheritanceAssembler>>> ({{{./apidocs/org/apache/maven/model/inheritance/InheritanceAssembler.html}javadoc}}),
with its <<<DefaultInheritanceAssembler>>> implementation
({{{./xref/org/apache/maven/model/inheritance/DefaultInheritanceAssembler.html}source}}). Notice that
<<<project.url>>>, <<<project.scm.connection>>>, <<<project.scm.developerConnection>>>, <<<project.scm.url>>> and
<<<project.distributionManagement.site.url>>> have a special treatment: if not overridden in child, the default value is parent's one
with child artifact id appended
[]
** model interpolation (see below)
* phase 2, with optional plugin processing
** dependency management import (for dependencies of type <<<pom>>> in the <<<\<dependencyManagement\>>>> section)
** inheritance assembly (see {{{./index.html#Inheritance_Assembly}below}})
** model interpolation (see {{{./index.html#Model_Interpolation}below}})
** url normalization: <<<UrlNormalizer>>> ({{{./apidocs/org/apache/maven/model/path/UrlNormalizer.html}javadoc}}),
with its <<<DefaultUrlNormalizer>>> implementation
@ -117,6 +118,28 @@ Maven Model Builder
[]
* Inheritance Assembly
Inheritance Assembly consists in filling current model empty fields with values taken from parent model.
It is done in <<<InheritanceAssembler>>> ({{{./apidocs/org/apache/maven/model/inheritance/InheritanceAssembler.html}javadoc}}),
with its <<<DefaultInheritanceAssembler>>> implementation
({{{./xref/org/apache/maven/model/inheritance/DefaultInheritanceAssembler.html}source}}).
By default, every model field is inherited as-is from parent, with a few exceptions that are intentionally not inherited:
<<<modelVersion>>>, <<<artifactId>>>, <<<profiles>>> (injected in phase 1) and <<<prerequisites>>>.
Notice that the 5 URLs from the model (<<<project.url>>>, <<<project.scm.connection>>>, <<<project.scm.developerConnection>>>,
<<<project.scm.url>>> and <<<project.distributionManagement.site.url>>>) have a special inheritance handling:
** if not configured in current model, the inherited value is the parent's one with current artifact id appended,
** since Maven 3.5.0, if <<<project.directory>>> POM property value is defined, it is used instead of artifact id:
this permits default inheritance calculations when module directory name is not equal to artifact id. Notice that this
property is not inherited from a POM to its child: childs POM will use child artifact id if property is not
set.
[]
* Model Interpolation
Model Interpolation consists in replacing <<<$\{...\}>>> with calculated value. It is done in <<<StringSearchModelInterpolator>>>

View File

@ -35,6 +35,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
/**
* @author Hervé Boutemy
@ -112,12 +113,13 @@ public class DefaultInheritanceAssemblerTest
{
// build from disk expected to fail
testInheritance( "tricky-flat-artifactId-urls", false );
fail( "should have failed since module reference == artifactId != directory name" );
//fail( "should have failed since module reference == artifactId != directory name" );
}
catch ( AssertionFailedError afe )
{
// expected failure: wrong relative path calculation
assertTrue( afe.getMessage().contains( "http://www.apache.org/path/to/parent/child-artifact-id/" ) );
assertTrue( afe.getMessage(),
afe.getMessage().contains( "http://www.apache.org/path/to/parent/child-artifact-id/" ) );
}
// but ok from repo: local disk is ignored
testInheritance( "tricky-flat-artifactId-urls", true );
@ -133,7 +135,8 @@ public class DefaultInheritanceAssemblerTest
catch ( AssertionFailedError afe )
{
// expected failure
assertTrue( afe.getMessage().contains( "http://www.apache.org/path/to/parent/child-artifact-id/" ) );
assertTrue( afe.getMessage(),
afe.getMessage().contains( "http://www.apache.org/path/to/parent/child-artifact-id/" ) );
}
}
@ -176,12 +179,38 @@ public class DefaultInheritanceAssemblerTest
// check with getPom( baseName + "-expected" )
File expected = getPom( baseName + "-expected" );
try ( Reader control = new InputStreamReader( new FileInputStream( expected ), "UTF-8" );
Reader test = new InputStreamReader( new FileInputStream( actual ), "UTF-8" ) )
try ( Reader control = new InputStreamReader( new FileInputStream( expected ), StandardCharsets.UTF_8 );
Reader test = new InputStreamReader( new FileInputStream( actual ), StandardCharsets.UTF_8 ) )
{
XMLUnit.setIgnoreComments( true );
XMLUnit.setIgnoreWhitespace( true );
XMLAssert.assertXMLEqual( control, test );
}
}
public void testModulePathNotArtifactId()
throws Exception
{
Model parent = getModel( "module-path-not-artifactId-parent" );
Model child = getModel( "module-path-not-artifactId-child" );
SimpleProblemCollector problems = new SimpleProblemCollector();
assembler.assembleModelInheritance( child, parent, null, problems );
File actual = getTestFile( "target/test-classes/poms/inheritance/module-path-not-artifactId-actual.xml" );
writer.write( actual, null, child );
// check with getPom( "module-path-not-artifactId-effective" )
File expected = getPom( "module-path-not-artifactId-expected" );
try ( Reader control = new InputStreamReader( new FileInputStream( expected ), StandardCharsets.UTF_8 );
Reader test = new InputStreamReader( new FileInputStream( actual ), StandardCharsets.UTF_8 ) )
{
XMLUnit.setIgnoreComments( true );
XMLUnit.setIgnoreWhitespace( true );
XMLAssert.assertXMLEqual( control, test );
}
}
}

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>inheritance</groupId>
<artifactId>parent</artifactId>
<version>11-SNAPSHOT</version>
</parent>
<artifactId>child-artifact-id</artifactId>
<name>Model inheritance test parent: module directory != artifactId</name>
<description>
artifactId == "child-artifact-id"
but expect path on SCM and site == "child"
feature: support "project.directory" property, ressembling future model addition of "directory" element along "artifactId"
</description>
<properties>
<project.directory>child</project.directory>
</properties>
</project>

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>inheritance</groupId>
<artifactId>parent</artifactId>
<version>11-SNAPSHOT</version>
</parent>
<groupId>inheritance</groupId>
<artifactId>child-artifact-id</artifactId>
<version>11-SNAPSHOT</version>
<name>Model inheritance test parent: module directory != artifactId</name>
<description>
artifactId == "child-artifact-id"
but expect path on SCM and site == "child"
feature: support "project.directory" property, ressembling future model addition of "directory" element along "artifactId"
</description>
<!-- 5 inherited urls with ${project.directory} added to parent instead of artifactId -->
<url>http://www.apache.org/child/</url>
<scm>
<connection>scm:my-scm:http://domain.org/base/child</connection>
<developerConnection>scm:my-scm:https://domain.org/base/child/</developerConnection>
<url>https://domain.org/base/child</url>
</scm>
<distributionManagement>
<site>
<url>scp://scp.domain.org/base/child/</url>
</site>
</distributionManagement>
<properties>
<project.directory>child</project.directory>
</properties>
</project>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>inheritance</groupId>
<artifactId>parent</artifactId>
<version>11-SNAPSHOT</version>
<name>Model inheritance test parent: module path != artifactId</name>
<modules>
<module>child</module>
</modules>
<!-- 5 URLs in the pom will be inherited with path added -->
<url>http://www.apache.org/</url>
<scm>
<connection>scm:my-scm:http://domain.org/base</connection>
<developerConnection>scm:my-scm:https://domain.org/base/</developerConnection>
<url>https://domain.org/base</url>
</scm>
<distributionManagement>
<site>
<url>scp://scp.domain.org/base/</url>
</site>
</distributionManagement>
</project>

View File

@ -245,7 +245,7 @@
<description>
<![CDATA[
The URL to the project's homepage.
<br /><b>Default value is</b>: parent value [+ path adjustment] + artifactId
<br /><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or <code>project.directory</code> property)
]]>
</description>
<type>String</type>
@ -2142,7 +2142,7 @@
<a href="https://maven.apache.org/scm/scm-url-format.html">URL format</a>
and <a href="https://maven.apache.org/scm/scms-overview.html">list of supported SCMs</a>.
This connection is read-only.
<br /><b>Default value is</b>: parent value [+ path adjustment] + artifactId
<br /><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or <code>project.directory</code> property)
]]>
</description>
<type>String</type>
@ -2154,7 +2154,7 @@
<![CDATA[
Just like <code>connection</code>, but for developers, i.e. this scm connection
will not be read only.
<br /><b>Default value is</b>: parent value [+ path adjustment] + artifactId
<br /><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or <code>project.directory</code> property)
]]>
</description>
<type>String</type>
@ -2172,7 +2172,7 @@
<description>
<![CDATA[
The URL to the project's browsable SCM repository, such as ViewVC or Fisheye.
<br /><b>Default value is</b>: parent value [+ path adjustment] + artifactId
<br /><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or <code>project.directory</code> property)
]]>
</description>
<type>String</type>
@ -2605,7 +2605,7 @@
<description>
<![CDATA[
The url of the location where website is deployed, in the form <code>protocol://hostname/path</code>.
<br /><b>Default value is</b>: parent value [+ path adjustment] + artifactId
<br /><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or <code>project.directory</code> property)
]]>
</description>
<type>String</type>