Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

GROOVY-3897: Add new Grape Ivy resolvers at runtime

git-svn-id: http://svn.codehaus.org/groovy/trunk/groovy/groovy-core@18435 a5544e8c-8a19-0410-ba12-f9af4593a198
  • Loading branch information...
commit 606a6ad3af01920d92dd751d99b84579337bfab3 1 parent 23f6bd3
@paulk-asert paulk-asert authored
View
4 pom.xml
@@ -502,6 +502,10 @@
<name>John Hurst</name>
<email></email>
</contributor>
+ <contributor>
+ <name>Merlyn Albery-Speyer</name>
+ <email></email>
+ </contributor>
</contributors>
<dependencies>
View
54 src/main/groovy/grape/GrabAnnotationTransformation.java
@@ -17,6 +17,7 @@
package groovy.grape;
import groovy.lang.Grab;
+import groovy.lang.GrabResolver;
import groovy.lang.Grapes;
import groovy.lang.GrabExclude;
import groovy.lang.GrabConfig;
@@ -56,8 +57,13 @@
private static final String GRAPES_DOT_NAME = dotName(GRAPES_CLASS_NAME);
private static final String GRAPES_SHORT_NAME = shortName(GRAPES_DOT_NAME);
+ private static final String GRABRESOLVER_CLASS_NAME = GrabResolver.class.getName();
+ private static final String GRAPERESOLVER_DOT_NAME = dotName(GRABRESOLVER_CLASS_NAME);
+ private static final String GRABRESOLVER_SHORT_NAME = shortName(GRAPERESOLVER_DOT_NAME);
+
private static final ClassNode THREAD_CLASSNODE = new ClassNode(Thread.class);
private static final List<String> GRABEXCLUDE_REQUIRED = Arrays.asList("group", "module");
+ private static final List<String> GRAPERESOLVER_REQUIRED = Arrays.asList("name", "root");
private static final List<String> GRAB_REQUIRED = Arrays.asList("group", "module", "version");
private static final List<String> GRAB_OPTIONAL = Arrays.asList("classifier", "transitive", "conf", "ext");
private static final Collection<String> GRAB_ALL = DefaultGroovyMethods.plus(GRAB_REQUIRED, GRAB_OPTIONAL);
@@ -87,6 +93,10 @@ private static String shortName(String className) {
Set<String> grapesAliases;
List<AnnotationNode> grapesAnnotations;
+ boolean allowShortGrabResolver;
+ Set<String> grabResolverAliases;
+ List<AnnotationNode> grabResolverAnnotations;
+
SourceUnit sourceUnit;
ClassLoader loader;
boolean initContextClassLoader;
@@ -106,10 +116,12 @@ public void visit(ASTNode[] nodes, SourceUnit source) {
allowShortGrabExcludes = true;
allowShortGrabConfig = true;
allowShortGrapes = true;
+ allowShortGrabResolver = true;
grabAliases = new HashSet<String>();
grabExcludeAliases = new HashSet<String>();
grabConfigAliases = new HashSet<String>();
grapesAliases = new HashSet<String>();
+ grabResolverAliases = new HashSet<String>();
for (ImportNode im : mn.getImports()) {
String alias = im.getAlias();
String className = im.getClassName();
@@ -127,6 +139,13 @@ public void visit(ASTNode[] nodes, SourceUnit source) {
} else if (GRAPES_CLASS_NAME.equals(className)) {
grapesAliases.add(im.getAlias());
}
+ if ((className.endsWith(GRAPERESOLVER_DOT_NAME) && ((alias == null) || (alias.length() == 0)))
+ || (GRABRESOLVER_CLASS_NAME.equals(alias)))
+ {
+ allowShortGrabResolver = false;
+ } else if (GRABRESOLVER_CLASS_NAME.equals(className)) {
+ grabResolverAliases.add(im.getAlias());
+ }
}
List<Map<String,Object>> grabMaps = new ArrayList<Map<String,Object>>();
@@ -137,11 +156,31 @@ public void visit(ASTNode[] nodes, SourceUnit source) {
grabExcludeAnnotations = new ArrayList<AnnotationNode>();
grabConfigAnnotations = new ArrayList<AnnotationNode>();
grapesAnnotations = new ArrayList<AnnotationNode>();
-
+ grabResolverAnnotations = new ArrayList<AnnotationNode>();
+
visitClass(classNode);
ClassNode grapeClassNode = new ClassNode(Grape.class);
+ if (!grabResolverAnnotations.isEmpty()) {
+ grabResolverAnnotationLoop:
+ for (AnnotationNode node : grabResolverAnnotations) {
+ Map<String, Object> grapeResolverMap = new HashMap<String, Object>();
+ for (String s : GRAPERESOLVER_REQUIRED) {
+ Expression member = node.getMember(s);
+ if (member == null) {
+ addError("The missing attribute \"" + s + "\" is required in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
+ continue grabResolverAnnotationLoop;
+ } else if (member != null && !(member instanceof ConstantExpression)) {
+ addError("Attribute \"" + s + "\" has value " + member.getText() + " but should be an inline constant in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
+ continue grabResolverAnnotationLoop;
+ }
+ grapeResolverMap.put(s, ((ConstantExpression)member).getValue());
+ }
+ Grape.addResolver(grapeResolverMap);
+ }
+ }
+
if (!grapesAnnotations.isEmpty()) {
for (AnnotationNode node : grapesAnnotations) {
Expression init = node.getMember("initClass");
@@ -210,9 +249,8 @@ public void visit(ASTNode[] nodes, SourceUnit source) {
callGrabAsStaticInitIfNeeded(classNode, grapeClassNode, node, grabExcludeMaps);
}
}
-
-
}
+
if (!grabMaps.isEmpty()) {
Map<String, Object> basicArgs = new HashMap<String, Object>();
basicArgs.put("classLoader", loader != null ? loader : sourceUnit.getClassLoader());
@@ -371,6 +409,11 @@ private void extractGrab(Expression init, ConstantExpression ce) {
|| (grabConfigAliases.contains(name))) {
grabConfigAnnotations.add(annotation);
}
+ if ((GRABRESOLVER_CLASS_NAME.equals(name))
+ || (allowShortGrabResolver && GRABRESOLVER_SHORT_NAME.equals(name))
+ || (grabResolverAliases.contains(name))) {
+ grabResolverAnnotations.add(annotation);
+ }
}
}
@@ -403,6 +446,11 @@ public void visitAnnotations(AnnotatedNode node) {
|| (grapesAliases.contains(name))) {
grapesAnnotations.add(an);
}
+ if ((GRABRESOLVER_CLASS_NAME.equals(name))
+ || (allowShortGrabResolver && GRABRESOLVER_SHORT_NAME.equals(name))
+ || (grabResolverAliases.contains(name))) {
+ grabResolverAnnotations.add(an);
+ }
}
}
View
11 src/main/groovy/grape/Grape.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 the original author or authors.
+ * Copyright 2008-2009 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.
@@ -197,5 +197,14 @@ public static void grab(Map<String, Object> args, Map... dependencies) {
}
}
+
+ public static void addResolver(Map<String, Object> args) {
+ if (enableGrapes) {
+ GrapeEngine instance = getInstance();
+ if (instance != null) {
+ instance.addResolver(args);
+ }
+ }
+ }
}
View
2  src/main/groovy/grape/GrapeEngine.java
@@ -39,5 +39,7 @@
URI[] resolve(Map args, List depsInfo, Map... dependencies);
Map[] listDependencies(ClassLoader classLoader);
+
+ void addResolver(Map<String, Object> args);
}
View
17 src/main/groovy/grape/GrapeIvy.groovy
@@ -32,6 +32,8 @@ import org.apache.ivy.plugins.matcher.ExactPatternMatcher
import org.apache.ivy.plugins.matcher.PatternMatcher
import org.apache.ivy.core.module.id.ModuleId
import org.apache.ivy.core.module.id.ArtifactId
+import org.apache.ivy.plugins.resolver.ChainResolver
+import org.apache.ivy.plugins.resolver.IBiblioResolver
/**
* @author Danno Ferrin
@@ -55,6 +57,8 @@ class GrapeIvy implements GrapeEngine {
Map<ClassLoader, Set<IvyGrabRecord>> loadedDeps = new WeakHashMap<ClassLoader, Set<IvyGrabRecord>>()
// set that stores the IvyGrabRecord(s) for all the dependencies in each grab() call
Set<IvyGrabRecord> grabRecordsForCurrDepdendencies = new LinkedHashSet<IvyGrabRecord>()
+ // we keep the settings so that addResolver can add to the resolver chain
+ IvySettings settings
public GrapeIvy() {
// if we are already inited, quit
@@ -62,7 +66,7 @@ class GrapeIvy implements GrapeEngine {
// start ivy
Message.setDefaultLogger(new DefaultMessageLogger(-1))
- IvySettings settings = new IvySettings()
+ settings = new IvySettings()
// configure settings
def grapeConfig = getLocalGrapeConfig()
@@ -435,6 +439,17 @@ class GrapeIvy implements GrapeEngine {
return null
}
}
+
+ public void addResolver(Map<String, Object> args) {
+ ChainResolver chainResolver = settings.getResolver("downloadGrapes")
+
+ IBiblioResolver resolver = new IBiblioResolver(name: args.name, root:args.root,
+ m2compatible:(args.m2Compatible ?: true), settings:settings)
+
+ chainResolver.add(resolver)
+
+ ivyInstance = Ivy.newInstance(settings)
+ }
}
class IvyGrabRecord {
View
48 src/main/groovy/lang/GrabResolver.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2003-2009 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 groovy.lang;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * Used to add a repository for resolving Grape dependencies
+ * <p/>
+ * For example:
+ * <pre>
+ * {@code @GrabResolver}(name='restlet.org', root='http://maven.restlet.org')
+ * {@code @Grab}(group='org.restlet', module='org.restlet', version='1.1.6')
+ * class MyRestlet extends org.restlet.Restlet {
+ * // ...
+ * }
+ * </pre>
+ * @author Merlyn Albery-Speyer
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({
+ ElementType.CONSTRUCTOR,
+ ElementType.FIELD,
+ ElementType.LOCAL_VARIABLE,
+ ElementType.METHOD,
+ ElementType.PARAMETER,
+ ElementType.TYPE})
+public @interface GrabResolver {
+ String name();
+ String root();
+ boolean m2Compatible() default true;
+}
View
67 src/test/groovy/grape/GrabResolverTest.groovy
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2008-2009 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 groovy.grape
+
+import org.codehaus.groovy.control.CompilationFailedException
+
+/**
+ * @author Merlyn Albery-Speyer
+ */
+class GrabResolverTest extends GroovyTestCase {
+ def originalGrapeRoot
+ def grapeRoot
+
+ public void setUp() {
+ Grape.@instance = null // isolate our test from other tests
+
+ // create a new grape root directory so as to insure a clean slate for this test
+ originalGrapeRoot = System.getProperty("grape.root")
+ grapeRoot = new File(System.getProperty("java.io.tmpdir"), "GrabResolverTest${System.currentTimeMillis()}")
+ assert grapeRoot.mkdir()
+ grapeRoot.deleteOnExit()
+ System.setProperty("grape.root", grapeRoot.path)
+ }
+
+ public void tearDown() {
+ if (originalGrapeRoot == null) {
+ // SDN bug: 4463345
+ System.getProperties().remove("grape.root")
+ } else {
+ System.setProperty("grape.root", originalGrapeRoot)
+ }
+
+ Grape.@instance = null // isolate our test from other tests
+ }
+
+ public void testResolverDefinitionIsRequired() {
+ GroovyShell shell = new GroovyShell(new GroovyClassLoader())
+ shouldFail(CompilationFailedException) {
+ shell.evaluate("""
+ @Grab(group='org.restlet', module='org.restlet', version='1.1.6')
+ class AnnotationHost {}
+ import org.restlet.Application""")
+ }
+ }
+
+ public void testResolverDefinitionResolvesDependency() {
+ GroovyShell shell = new GroovyShell(new GroovyClassLoader())
+ shell.evaluate("""
+ @GrabResolver(name='restlet.org', root='http://maven.restlet.org')
+ @Grab(group='org.restlet', module='org.restlet', version='1.1.6')
+ class AnnotationHost {}
+ assert org.restlet.Application.class.simpleName == 'Application'""")
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.