Skip to content

Commit

Permalink
Map version range '+' syntax to maven syntax when generating pom file
Browse files Browse the repository at this point in the history
- use in maven-publish and maven plugin
- todo add support for 'RELEASE' and 'LATEST'

+review REVIEW-5225
  • Loading branch information
breskeby committed Oct 9, 2014
1 parent 3749ec1 commit c1ef0d8
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 6 deletions.
Expand Up @@ -36,7 +36,7 @@ public Factory<MavenPom> createMavenPomFactory(ConfigurationContainer configurat
}

private PomDependenciesConverter createPomDependenciesConverter() {
return new DefaultPomDependenciesConverter(new DefaultExcludeRuleConverter());
return new DefaultPomDependenciesConverter(new DefaultExcludeRuleConverter(), new MavenVersionRangeMapper());
}

public Conf2ScopeMappingContainer createConf2ScopeMappingContainer(Map<Configuration, Conf2ScopeMapping> mappings) {
Expand Down
@@ -0,0 +1,44 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.gradle.api.publication.maven.internal;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MavenVersionRangeMapper implements VersionRangeMapper{

private static final String FIXED_PREFIX = "([\\d\\.]*)";
private static final String DYN_VERSION_NUMBER = "(\\d+)";
public static final String PLUS_OPER = "[\\.]?\\+";
private static final String PLUS_NOTATION_PATTERN = FIXED_PREFIX + DYN_VERSION_NUMBER + PLUS_OPER;

public final Pattern plusNotationPattern = Pattern.compile(PLUS_NOTATION_PATTERN);

public String map(String version) {
Matcher plusNotationMatcher = plusNotationPattern.matcher(version);
if(plusNotationMatcher.matches()){
String prefix = plusNotationMatcher.group(1);
int dynVersionPart = Integer.parseInt(plusNotationMatcher.group(2));
if(prefix!=null){
return String.format("[%s%s,%s%s)", prefix, dynVersionPart, prefix, dynVersionPart+1);
} else{
return String.format("[%s,%s)", dynVersionPart, dynVersionPart+1);
}
}
return version;
}
}
@@ -0,0 +1,21 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.gradle.api.publication.maven.internal;

public interface VersionRangeMapper {
String map(String version);
}
Expand Up @@ -23,14 +23,17 @@
import org.gradle.api.artifacts.maven.Conf2ScopeMappingContainer;
import org.gradle.api.publication.maven.internal.ExcludeRuleConverter;
import org.gradle.api.publication.maven.internal.PomDependenciesConverter;
import org.gradle.api.publication.maven.internal.VersionRangeMapper;

import java.util.*;

public class DefaultPomDependenciesConverter implements PomDependenciesConverter {
private ExcludeRuleConverter excludeRuleConverter;
private VersionRangeMapper versionRangeMapper;

public DefaultPomDependenciesConverter(ExcludeRuleConverter excludeRuleConverter) {
public DefaultPomDependenciesConverter(ExcludeRuleConverter excludeRuleConverter, VersionRangeMapper versionRangeMapper) {
this.excludeRuleConverter = excludeRuleConverter;
this.versionRangeMapper = versionRangeMapper;
}

public List<org.apache.maven.model.Dependency> convert(Conf2ScopeMappingContainer conf2ScopeMappingContainer, Set<Configuration> configurations) {
Expand Down Expand Up @@ -119,7 +122,7 @@ private Dependency createMavenDependency(ModuleDependency dependency, String nam
} else {
mavenDependency.setArtifactId(name);
}
mavenDependency.setVersion(dependency.getVersion());
mavenDependency.setVersion(mapToMavenSyntax(dependency.getVersion()));
mavenDependency.setType(type);
mavenDependency.setScope(scope);
mavenDependency.setOptional(false);
Expand All @@ -128,6 +131,10 @@ private Dependency createMavenDependency(ModuleDependency dependency, String nam
return mavenDependency;
}

private String mapToMavenSyntax(String version) {
return versionRangeMapper.map(version);
}

protected String determineProjectDependencyArtifactId(ProjectDependency dependency) {
return new ProjectDependencyArtifactIdExtractorHack(dependency).extract();
}
Expand Down
Expand Up @@ -25,9 +25,11 @@
import org.gradle.api.XmlProvider;
import org.gradle.api.artifacts.DependencyArtifact;
import org.gradle.api.artifacts.ExcludeRule;
import org.gradle.internal.xml.XmlTransformer;
import org.gradle.api.publication.maven.internal.MavenVersionRangeMapper;
import org.gradle.api.publication.maven.internal.VersionRangeMapper;
import org.gradle.api.publish.maven.internal.dependencies.MavenDependencyInternal;
import org.gradle.api.publish.maven.internal.publisher.MavenProjectIdentity;
import org.gradle.internal.xml.XmlTransformer;
import org.gradle.util.GUtil;

import java.io.File;
Expand All @@ -41,6 +43,7 @@ public class MavenPomFileGenerator {

private MavenProject mavenProject = new MavenProject();
private XmlTransformer xmlTransformer = new XmlTransformer();
private VersionRangeMapper versionRangeMapper= new MavenVersionRangeMapper();

public MavenPomFileGenerator(MavenProjectIdentity identity) {
mavenProject.setModelVersion(POM_VERSION);
Expand Down Expand Up @@ -77,7 +80,7 @@ private void addDependency(MavenDependencyInternal dependency, String artifactId
Dependency mavenDependency = new Dependency();
mavenDependency.setGroupId(dependency.getGroupId());
mavenDependency.setArtifactId(artifactId);
mavenDependency.setVersion(dependency.getVersion());
mavenDependency.setVersion(mapToMavenSyntax(dependency.getVersion()));
mavenDependency.setType(type);
mavenDependency.setScope(scope);
mavenDependency.setClassifier(classifier);
Expand All @@ -92,6 +95,10 @@ private void addDependency(MavenDependencyInternal dependency, String artifactId
getModel().addDependency(mavenDependency);
}

private String mapToMavenSyntax(String version) {
return versionRangeMapper.map(version);
}

public MavenPomFileGenerator withXml(final Action<XmlProvider> action) {
xmlTransformer.addAction(action);
return this;
Expand Down
@@ -0,0 +1,43 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.gradle.api.publication.maven.internal

import spock.lang.Specification
import spock.lang.Unroll

class MavenVersionRangeMapperSpec extends Specification {
def mapper = new MavenVersionRangeMapper()

@Unroll
def "maps '#input' to '#output'"() {
expect:
mapper.map(input) == output
where:
input | output
"1.0" | "1.0"
"1+" | "[1,2)"

This comment has been minimized.

Copy link
@mosabua

mosabua Oct 21, 2014

This is wrong. Should be "[1,)"

This comment has been minimized.

Copy link
@mosabua

mosabua Oct 21, 2014

Unless I am misinterpreting what 1+ means in the ivy world. From what I can tell now reading the ivy docs.. you are correct. However this seems completely counter-intuitive... but oh well.

This comment has been minimized.

Copy link
@breskeby

breskeby Oct 22, 2014

Author Contributor

yeah in ivy '+' just means any latest sub-revision. that can be a bit misleading

"1.+" | "[1,2)"

This comment has been minimized.

Copy link
@mosabua

mosabua Oct 21, 2014

I am not sure what this implies on the Gradle side. It might be correct. No upper bound is typically signified by no value.. but the plus actually seems to be more like a * in terms of pattern matching.

This comment has been minimized.

Copy link
@mosabua

mosabua Oct 21, 2014

Also brackets usage follows https://en.wikipedia.org/wiki/Interval_(mathematics e.g. square brackets include =, round ones dont.

This comment has been minimized.

Copy link
@breskeby

breskeby Oct 22, 2014

Author Contributor

Understood. apart from having plain '+' which is mapped to LATEST now ivy 'x.+' syntax always has an exclusive upper bound

"1.5.+" | "[1.5,1.6)"
"1.5+" | "[1.5,1.6)"
"1.100+" | "[1.100,1.101)"

This comment has been minimized.

Copy link
@mosabua

mosabua Oct 21, 2014

Weird.. but according to the ivy specs this is fine.

"10.1+" | "[10.1,10.2)"

// TODO map LATEST & RELEASE (first support on our pom parsing must be added)
// "latest.integration" | "LATEST"
// "latest.release" | "RELEASE"
}
}
Expand Up @@ -23,6 +23,7 @@
import org.gradle.api.internal.artifacts.dependencies.DefaultDependencyArtifact;
import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency;
import org.gradle.api.publication.maven.internal.ExcludeRuleConverter;
import org.gradle.api.publication.maven.internal.VersionRangeMapper;
import org.gradle.util.JUnit4GroovyMockery;
import org.gradle.util.WrapUtil;
import org.jmock.Expectations;
Expand All @@ -48,6 +49,7 @@ public class DefaultPomDependenciesConverterTest {
private DefaultPomDependenciesConverter dependenciesConverter;
private Conf2ScopeMappingContainer conf2ScopeMappingContainerMock = context.mock(Conf2ScopeMappingContainer.class);
private ExcludeRuleConverter excludeRuleConverterMock = context.mock(ExcludeRuleConverter.class);
private VersionRangeMapper versionRangeMapper = context.mock(VersionRangeMapper.class);

private ModuleDependency dependency1;
private ModuleDependency dependency2;
Expand All @@ -59,7 +61,8 @@ public class DefaultPomDependenciesConverterTest {
@Before
public void setUp() {
setUpCommonDependenciesAndConfigurations();
dependenciesConverter = new DefaultPomDependenciesConverter(excludeRuleConverterMock);
dependenciesConverter = new DefaultPomDependenciesConverter(excludeRuleConverterMock, versionRangeMapper);

}

private void setUpCommonDependenciesAndConfigurations() {
Expand All @@ -76,6 +79,9 @@ private void setUpCommonDependenciesAndConfigurations() {
allowing(conf2ScopeMappingContainerMock).getMapping(toSet(compileConfStub, testCompileConfStub)); will(returnValue(createMapping(testCompileConfStub, "test")));
allowing(conf2ScopeMappingContainerMock).getMapping(toSet(testCompileConfStub)); will(returnValue(createMapping(testCompileConfStub, "test")));
allowing(conf2ScopeMappingContainerMock).getMapping(toSet(compileConfStub)); will(returnValue(createMapping(compileConfStub, "compile")));
allowing(versionRangeMapper).map("rev1"); will(returnValue("rev1"));
allowing(versionRangeMapper).map("rev2"); will(returnValue("rev2"));
allowing(versionRangeMapper).map("rev3"); will(returnValue("rev3"));
}});
}

Expand Down Expand Up @@ -149,6 +155,7 @@ public void convertWithUnMappedConfAndSkipFalse() {
context.checking(new Expectations() {{
allowing(conf2ScopeMappingContainerMock).isSkipUnmappedConfs(); will(returnValue(false));
allowing(conf2ScopeMappingContainerMock).getMapping(toSet(unmappedConfigurationStub)); will(returnValue(new Conf2ScopeMapping(null, unmappedConfigurationStub, null)));
allowing(versionRangeMapper).map("rev4"); will(returnValue("rev4"));
}});
List<org.apache.maven.model.Dependency> actualMavenDependencies = dependenciesConverter.convert(conf2ScopeMappingContainerMock, toSet(
compileConfStub, testCompileConfStub, unmappedConfigurationStub));
Expand Down
Expand Up @@ -203,6 +203,41 @@ class MavenPomFileGeneratorTest extends Specification {
}
}

def "maps version range to maven syntax"() {
def dependency1 = Mock(MavenDependencyInternal)
def dependency2 = Mock(MavenDependencyInternal)

when:
generator.addRuntimeDependency(dependency1)
generator.addRuntimeDependency(dependency2)

then:
dependency1.artifacts >> new HashSet<DependencyArtifact>()
dependency1.groupId >> "dep-group"
dependency1.version >> "1+"
dependency1.excludeRules >> []

dependency2.artifacts >> new HashSet<DependencyArtifact>()
dependency2.groupId >> "dep-group"
dependency2.version >> "1.100.+"
dependency2.excludeRules >> []

and:
with (pom) {
dependencies.dependency.size() == 2
with (dependencies[0].dependency[0]) {
groupId == "dep-group"
version == "[1,2)"
scope == "runtime"
}
with (dependencies[0].dependency[1]) {
groupId == "dep-group"
version == "[1.100,1.101)"
scope == "runtime"
}
}
}

def "applies withXml actions"() {
when:
generator.withXml(new Action<XmlProvider>() {
Expand Down

0 comments on commit c1ef0d8

Please sign in to comment.