Support transitive=false in AetherGrapeEngine

@Grab allows a dependency to be declared, but for its transitive
dependencies to be excluded by setting transitive to false. This
commit enhances AetherGrapeEngine to honour this setting by using a
wildcard exclusion on any dependency so declared.
This commit is contained in:
Andy Wilkinson 2013-10-24 13:57:38 +01:00
parent 97cb7f0967
commit 1d5cb7731d
4 changed files with 141 additions and 18 deletions

View File

@ -24,6 +24,7 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@ -39,6 +40,7 @@ import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.Exclusion;
import org.eclipse.aether.impl.ArtifactDescriptorReader;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.internal.impl.DefaultRepositorySystem;
@ -77,6 +79,9 @@ public class AetherGrapeEngine implements GrapeEngine {
private static final String DEPENDENCY_VERSION = "version";
private static final Collection<Exclusion> WILDCARD_EXCLUSION = Arrays
.asList(new Exclusion("*", "*", "*", "*"));
private final Artifact parentArtifact;
private final ProgressReporter progressReporter = new ProgressReporter();
@ -190,15 +195,36 @@ public class AetherGrapeEngine implements GrapeEngine {
return dependencies;
}
private boolean isTransitive(Map<?, ?> dependencyMap) {
Boolean transitive = (Boolean) dependencyMap.get("transitive");
if (transitive == null) {
transitive = true;
}
return transitive;
}
private Dependency createDependency(Map<?, ?> dependencyMap) {
Artifact artifact = createArtifact(dependencyMap);
Dependency dependency;
if (!isTransitive(dependencyMap)) {
dependency = new Dependency(artifact, JavaScopes.COMPILE, null,
WILDCARD_EXCLUSION);
}
else {
dependency = new Dependency(artifact, JavaScopes.COMPILE);
}
return dependency;
}
private Artifact createArtifact(Map<?, ?> dependencyMap) {
String group = (String) dependencyMap.get(DEPENDENCY_GROUP);
String module = (String) dependencyMap.get(DEPENDENCY_MODULE);
String version = (String) dependencyMap.get(DEPENDENCY_VERSION);
// TODO Transitivity
Artifact artifact = new DefaultArtifact(group, module, "jar", version);
return new Dependency(artifact, JavaScopes.COMPILE);
return new DefaultArtifact(group, module, "jar", version);
}
private List<File> resolve(List<Dependency> dependencies)

View File

@ -0,0 +1,88 @@
/*
* Copyright 2012-2013 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.springframework.boot.cli.compiler;
import groovy.lang.GroovyClassLoader;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* @author Andy Wilkinson
*/
public class AetherGrapeEngineTests {
private final GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
private final AetherGrapeEngine grapeEngine = new AetherGrapeEngine(
this.groovyClassLoader, null, null, null);
@Test
public void dependencyResolution() {
Map<String, Object> args = new HashMap<String, Object>();
this.grapeEngine.grab(args,
createDependency("org.springframework", "spring-jdbc", "3.2.4.RELEASE"));
assertEquals(6, this.groovyClassLoader.getURLs().length);
}
@Test
public void nonTransitiveDependencyResolution() {
Map<String, Object> args = new HashMap<String, Object>();
this.grapeEngine.grab(
args,
createDependency("org.springframework", "spring-jdbc", "3.2.4.RELEASE",
false));
assertEquals(1, this.groovyClassLoader.getURLs().length);
}
@Test
public void dependencyResolutionWithCustomClassLoader() {
Map<String, Object> args = new HashMap<String, Object>();
GroovyClassLoader customClassLoader = new GroovyClassLoader();
args.put("classLoader", customClassLoader);
this.grapeEngine.grab(args,
createDependency("org.springframework", "spring-jdbc", "3.2.4.RELEASE"));
assertEquals(0, this.groovyClassLoader.getURLs().length);
assertEquals(6, customClassLoader.getURLs().length);
}
private Map<String, Object> createDependency(String group, String module,
String version) {
Map<String, Object> dependency = new HashMap<String, Object>();
dependency.put("group", group);
dependency.put("module", module);
dependency.put("version", version);
return dependency;
}
private Map<String, Object> createDependency(String group, String module,
String version, boolean transitive) {
Map<String, Object> dependency = createDependency(group, module, version);
dependency.put("transitive", transitive);
return dependency;
}
}

View File

@ -100,11 +100,17 @@
<resource>
<directory>src/main/groovy</directory>
</resource>
<resource>
<directory>${project.build.directory}/generated-resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<additionalClasspathElements>
<additionalClasspathElement>${project.build.directory}/generated-resources</additionalClasspathElement>
</additionalClasspathElements>
<classpathDependencyExcludes>
<classpathDependencyExcludes>org.springframework:spring-core</classpathDependencyExcludes>
<classpathDependencyExcludes>org.springframework:spring-beans</classpathDependencyExcludes>
@ -190,7 +196,7 @@
<property name="dependencies" value="${project.parent}" />
<vppcopy
file="${basedir}/src/main/resources/META-INF/springcli.properties.vpp"
tofile="${project.build.directory}/classes/META-INF/springcli.properties"
tofile="${project.build.directory}/generated-resources/META-INF/springcli.properties"
overwrite="true" />
</target>
</configuration>

View File

@ -353,30 +353,37 @@ public class GroovyCompiler {
}
private void transformGrabAnnotation(AnnotationNode grabAnnotation) {
grabAnnotation.setMember("initClass", new ConstantExpression(false));
Expression valueExpression = grabAnnotation.getMember("value");
String value = null;
if (valueExpression instanceof ConstantExpression) {
ConstantExpression constantExpression = (ConstantExpression) valueExpression;
Object valueObject = constantExpression.getValue();
if (valueObject instanceof String) {
String value = (String) valueObject;
if (!isConvenienceForm(value)) {
applyGroupAndVersion(grabAnnotation, constantExpression);
value = (String) valueObject;
if (isConvenienceForm(value)) {
return;
}
grabAnnotation.setMember("initClass", new ConstantExpression(false));
}
}
applyGroupAndVersion(grabAnnotation, value);
}
private boolean isConvenienceForm(String value) {
return value.contains(":") || value.contains("#");
}
private void applyGroupAndVersion(AnnotationNode grabAnnotation,
ConstantExpression moduleExpression) {
private void applyGroupAndVersion(AnnotationNode grabAnnotation, String module) {
grabAnnotation.setMember("module", moduleExpression);
String module = (String) moduleExpression.getValue();
if (module != null) {
grabAnnotation.setMember("module", new ConstantExpression(module));
}
else {
module = (String) ((ConstantExpression) grabAnnotation.getMembers().get(
"module")).getValue();
}
if (grabAnnotation.getMember("group") == null) {
ConstantExpression groupIdExpression = new ConstantExpression(
@ -391,10 +398,6 @@ public class GroovyCompiler {
.getVersion(module));
grabAnnotation.setMember("version", versionExpression);
}
grabAnnotation.setMember("initClass", new ConstantExpression(false));
}
}
}