diff --git a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java index 5fc7459db8..4786a03033 100644 --- a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java @@ -600,7 +600,7 @@ public class PomConstructionTest { PomTestWrapper pom = buildPom( "url-inheritance/sub" ); assertEquals( "http://parent.url/child", pom.getValue( "url" ) ); - assertEquals( "http://parent.url/org/", pom.getValue( "organization/url" ) ); + assertEquals( "http://parent.url/org", pom.getValue( "organization/url" ) ); assertEquals( "http://parent.url/license.txt", pom.getValue( "licenses[1]/url" ) ); assertEquals( "http://parent.url/viewvc/child", pom.getValue( "scm/url" ) ); assertEquals( "http://parent.url/scm/child", pom.getValue( "scm/connection" ) ); @@ -619,7 +619,7 @@ public class PomConstructionTest { PomTestWrapper pom = buildPom( "url-inheritance/another-parent/sub" ); assertEquals( "http://parent.url/ap/child", pom.getValue( "url" ) ); - assertEquals( "http://parent.url/org/", pom.getValue( "organization/url" ) ); + assertEquals( "http://parent.url/org", pom.getValue( "organization/url" ) ); assertEquals( "http://parent.url/license.txt", pom.getValue( "licenses[1]/url" ) ); assertEquals( "http://parent.url/viewvc/ap/child", pom.getValue( "scm/url" ) ); assertEquals( "http://parent.url/scm/ap/child", pom.getValue( "scm/connection" ) ); diff --git a/maven-core/src/test/resources-project-builder/unc-path/pom.xml b/maven-core/src/test/resources-project-builder/unc-path/pom.xml index 1e9035c487..be2a825ad7 100644 --- a/maven-core/src/test/resources-project-builder/unc-path/pom.xml +++ b/maven-core/src/test/resources-project-builder/unc-path/pom.xml @@ -35,7 +35,7 @@ site - file:////host/site/ + file:////host/site diff --git a/maven-core/src/test/resources-project-builder/url-inheritance/pom.xml b/maven-core/src/test/resources-project-builder/url-inheritance/pom.xml index 138cb6942d..4dc628f6fe 100644 --- a/maven-core/src/test/resources-project-builder/url-inheritance/pom.xml +++ b/maven-core/src/test/resources-project-builder/url-inheritance/pom.xml @@ -32,10 +32,10 @@ under the License. Test that inheritance of certain URLs automatically appends the child's artifact id. - http://parent.url/ + http://parent.url parent-org - http://parent.url/org/ + http://parent.url/org 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 b2b701adb6..a91a1e951f 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 @@ -45,6 +45,7 @@ import org.apache.maven.model.management.DependencyManagementInjector; import org.apache.maven.model.management.PluginManagementInjector; import org.apache.maven.model.normalization.ModelNormalizer; import org.apache.maven.model.path.ModelPathTranslator; +import org.apache.maven.model.path.ModelUrlNormalizer; import org.apache.maven.model.plugin.LifecycleBindingsInjector; import org.apache.maven.model.plugin.PluginConfigurationExpander; import org.apache.maven.model.plugin.ReportConfigurationExpander; @@ -83,6 +84,9 @@ public class DefaultModelBuilder @Requirement private ModelPathTranslator modelPathTranslator; + @Requirement + private ModelUrlNormalizer modelUrlNormalizer; + @Requirement private SuperPomProvider superPomProvider; @@ -225,6 +229,8 @@ public class DefaultModelBuilder resultModel = interpolateModel( resultModel, request, problems ); resultData.setModel( resultModel ); + modelUrlNormalizer.normalize( resultModel, request ); + resultData.setGroupId( resultModel.getGroupId() ); resultData.setArtifactId( resultModel.getArtifactId() ); resultData.setVersion( resultModel.getVersion() ); diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java index fad12b33e9..c8b3080bbc 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java @@ -24,6 +24,7 @@ import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelProblemCollector; import org.apache.maven.model.building.ModelProblem.Severity; import org.apache.maven.model.path.PathTranslator; +import org.apache.maven.model.path.UrlNormalizer; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.interpolation.AbstractValueSource; import org.codehaus.plexus.interpolation.InterpolationException; @@ -95,6 +96,9 @@ public abstract class AbstractStringBasedModelInterpolator @Requirement private PathTranslator pathTranslator; + @Requirement + private UrlNormalizer urlNormalizer; + private Interpolator interpolator; private RecursionInterceptor recursionInterceptor; @@ -187,16 +191,14 @@ public abstract class AbstractStringBasedModelInterpolator final File projectDir, final ModelBuildingRequest config ) { + List processors = new ArrayList( 2 ); if ( projectDir != null ) { - return Collections.singletonList( new PathTranslatingPostProcessor( PROJECT_PREFIXES, - TRANSLATED_PATH_EXPRESSIONS, - projectDir, pathTranslator ) ); - } - else - { - return Collections.emptyList(); + processors.add( new PathTranslatingPostProcessor( PROJECT_PREFIXES, TRANSLATED_PATH_EXPRESSIONS, + projectDir, pathTranslator ) ); } + processors.add( new UrlNormalizingPostProcessor( urlNormalizer ) ); + return processors; } protected String interpolateInternal( String src, List valueSources, diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PathTranslatingPostProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PathTranslatingPostProcessor.java index c930215089..df6c051946 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PathTranslatingPostProcessor.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PathTranslatingPostProcessor.java @@ -60,7 +60,7 @@ class PathTranslatingPostProcessor } } - return value; + return null; } } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/UrlNormalizingPostProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/UrlNormalizingPostProcessor.java new file mode 100644 index 0000000000..95109bcb50 --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/UrlNormalizingPostProcessor.java @@ -0,0 +1,68 @@ +package org.apache.maven.model.interpolation; + +/* + * 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.HashSet; +import java.util.Set; + +import org.apache.maven.model.path.UrlNormalizer; +import org.codehaus.plexus.interpolation.InterpolationPostProcessor; + +/** + * Ensures that expressions referring to URLs evaluate to normalized URLs. + * + * @author Benjamin Bentmann + */ +class UrlNormalizingPostProcessor + implements InterpolationPostProcessor +{ + + private static final Set urlExpressions; + + static + { + Set expressions = new HashSet(); + expressions.add( "project.url" ); + expressions.add( "project.scm.url" ); + expressions.add( "project.scm.connection" ); + expressions.add( "project.scm.developerConnection" ); + expressions.add( "project.distributionManagement.site.url" ); + + urlExpressions = expressions; + } + + private UrlNormalizer normalizer; + + public UrlNormalizingPostProcessor( UrlNormalizer normalizer ) + { + this.normalizer = normalizer; + } + + public Object execute( String expression, Object value ) + { + if ( value != null && urlExpressions.contains( expression ) ) + { + return normalizer.normalize( value.toString() ); + } + + return null; + } + +} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/merge/MavenModelMerger.java b/maven-model-builder/src/main/java/org/apache/maven/model/merge/MavenModelMerger.java index c08e90a5cc..9a1de0af09 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/merge/MavenModelMerger.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/merge/MavenModelMerger.java @@ -22,11 +22,9 @@ package org.apache.maven.model.merge; import java.util.ArrayList; 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.BuildBase; import org.apache.maven.model.CiManagement; @@ -560,80 +558,39 @@ public class MavenModelMerger private String appendPath( String parentPath, String childPath, String pathAdjustment ) { - String uncleanPath = parentPath; - - if ( pathAdjustment != null && pathAdjustment.length() > 0 ) - { - 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 ); + String path = parentPath; + path = concatPath( path, pathAdjustment ); + path = concatPath( path, childPath ); + return path; } - private String resolvePath( String uncleanPath ) + private String concatPath( String base, String path ) { - LinkedList pathElements = new LinkedList(); + String result = base; - StringTokenizer tokenizer = new StringTokenizer( uncleanPath, "/" ); - - while ( tokenizer.hasMoreTokens() ) + if ( path != null && path.length() > 0 ) { - String token = tokenizer.nextToken(); - - if ( token.equals( "" ) ) + if ( ( result.endsWith( "/" ) && !path.startsWith( "/" ) ) + || ( !result.endsWith( "/" ) && path.startsWith( "/" ) ) ) { - // Empty path entry ("...//.."), remove. + result += path; } - else if ( token.equals( ".." ) ) + else if ( result.endsWith( "/" ) && path.startsWith( "/" ) ) { - if ( !pathElements.isEmpty() ) - { - pathElements.removeLast(); - } + result += path.substring( 1 ); } else { - pathElements.addLast( token ); + result += '/'; + result += path; } - } - - StringBuilder cleanedPath = new StringBuilder( 128 ); - - while ( !pathElements.isEmpty() ) - { - cleanedPath.append( pathElements.removeFirst() ); - if ( !pathElements.isEmpty() ) + if ( base.endsWith( "/" ) && !result.endsWith( "/" ) ) { - cleanedPath.append( '/' ); + result += '/'; } } - return cleanedPath.toString(); + return result; } } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelUrlNormalizer.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelUrlNormalizer.java new file mode 100644 index 0000000000..d143999607 --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelUrlNormalizer.java @@ -0,0 +1,77 @@ +package org.apache.maven.model.path; + +/* + * 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.DistributionManagement; +import org.apache.maven.model.Model; +import org.apache.maven.model.Scm; +import org.apache.maven.model.Site; +import org.apache.maven.model.building.ModelBuildingRequest; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; + +/** + * Normalizes URLs to remove the ugly parent references "../" that got potentially inserted by URL adjustment during + * model inheritance. + * + * @author Benjamin Bentmann + */ +@Component( role = ModelUrlNormalizer.class ) +public class DefaultModelUrlNormalizer + implements ModelUrlNormalizer +{ + + @Requirement + private UrlNormalizer urlNormalizer; + + public void normalize( Model model, ModelBuildingRequest request ) + { + if ( model == null ) + { + return; + } + + model.setUrl( normalize( model.getUrl() ) ); + + Scm scm = model.getScm(); + if ( scm != null ) + { + scm.setUrl( normalize( scm.getUrl() ) ); + scm.setConnection( normalize( scm.getConnection() ) ); + scm.setDeveloperConnection( normalize( scm.getDeveloperConnection() ) ); + } + + DistributionManagement dist = model.getDistributionManagement(); + if ( dist != null ) + { + Site site = dist.getSite(); + if ( site != null ) + { + site.setUrl( normalize( site.getUrl() ) ); + } + } + } + + private String normalize( String url ) + { + return urlNormalizer.normalize( url ); + } + +} diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultUrlNormalizer.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultUrlNormalizer.java new file mode 100644 index 0000000000..8c22c45929 --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultUrlNormalizer.java @@ -0,0 +1,61 @@ +package org.apache.maven.model.path; + +/* + * 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.codehaus.plexus.component.annotations.Component; + +/** + * Normalizes a URL. + * + * @author Benjamin Bentmann + */ +@Component( role = UrlNormalizer.class ) +public class DefaultUrlNormalizer + implements UrlNormalizer +{ + + public String normalize( String url ) + { + String result = url; + + if ( result != null ) + { + result = result.replaceAll( "(?