diff --git a/grails-core/src/main/groovy/org/grails/core/cfg/GroovyConfigPropertySourceLoader.groovy b/grails-core/src/main/groovy/org/grails/core/cfg/GroovyConfigPropertySourceLoader.groovy index ee6f7c6d7ca..d1f19627735 100644 --- a/grails-core/src/main/groovy/org/grails/core/cfg/GroovyConfigPropertySourceLoader.groovy +++ b/grails-core/src/main/groovy/org/grails/core/cfg/GroovyConfigPropertySourceLoader.groovy @@ -41,7 +41,11 @@ class GroovyConfigPropertySourceLoader implements PropertySourceLoader { final String[] fileExtensions = ['groovy'] as String[] @Override - PropertySource load(String name, Resource resource, String profile) throws IOException { + PropertySource load(String name, Resource resource, String profile) { + load(name, resource, profile, []) + } + + PropertySource load(String name, Resource resource, String profile, List filteredKeys) throws IOException { def env = Environment.current.name if(profile == null || env == profile) { @@ -55,6 +59,11 @@ class GroovyConfigPropertySourceLoader implements PropertySourceLoader { appVersion: Metadata.getCurrent().getApplicationVersion() ) try { def configObject = configSlurper.parse(resource.URL) + + filteredKeys?.each { key -> + configObject.remove(key) + } + def propertySource = new NavigableMap() propertySource.merge(configObject, false) return new NavigableMapPropertySource(name, propertySource) diff --git a/grails-core/src/main/groovy/org/grails/plugins/AbstractGrailsPlugin.java b/grails-core/src/main/groovy/org/grails/plugins/AbstractGrailsPlugin.java index 8a96be2588c..33663d9ca7c 100644 --- a/grails-core/src/main/groovy/org/grails/plugins/AbstractGrailsPlugin.java +++ b/grails-core/src/main/groovy/org/grails/plugins/AbstractGrailsPlugin.java @@ -24,6 +24,7 @@ import groovy.lang.GroovyObjectSupport; import org.grails.config.yaml.YamlPropertySourceLoader; import org.grails.core.AbstractGrailsClass; +import org.grails.core.cfg.GroovyConfigPropertySourceLoader; import org.grails.core.legacy.LegacyGrailsApplication; import org.grails.plugins.support.WatchPattern; import org.slf4j.Logger; @@ -49,6 +50,8 @@ public abstract class AbstractGrailsPlugin extends GroovyObjectSupport implement public static final String PLUGIN_YML = "plugin.yml"; public static final String PLUGIN_YML_PATH = "/" + PLUGIN_YML; + public static final String PLUGIN_GROOVY = "plugin.groovy"; + public static final String PLUGIN_GROOVY_PATH = "/" + PLUGIN_GROOVY; private static final List DEFAULT_CONFIG_IGNORE_LIST = Arrays.asList("dataSource", "hibernate"); private static Resource basePluginResource = null; protected PropertySource propertySource; @@ -84,12 +87,19 @@ public AbstractGrailsPlugin(Class pluginClass, GrailsApplication application) this.grailsApplication = application; this.pluginClass = pluginClass; Resource resource = readPluginConfiguration(pluginClass); + if(resource != null && resource.exists()) { - YamlPropertySourceLoader propertySourceLoader = new YamlPropertySourceLoader(); + final String filename = resource.getFilename(); try { - this.propertySource = propertySourceLoader.load(GrailsNameUtils.getLogicalPropertyName(pluginClass.getSimpleName(), "GrailsPlugin") + "-plugin.yml", resource, null, false, DEFAULT_CONFIG_IGNORE_LIST); + if (filename.equals(PLUGIN_YML)) { + YamlPropertySourceLoader propertySourceLoader = new YamlPropertySourceLoader(); + this.propertySource = propertySourceLoader.load(GrailsNameUtils.getLogicalPropertyName(pluginClass.getSimpleName(), "GrailsPlugin") + "-" + PLUGIN_YML, resource, null, false, DEFAULT_CONFIG_IGNORE_LIST); + } else if (filename.equals(PLUGIN_GROOVY)) { + GroovyConfigPropertySourceLoader propertySourceLoader = new GroovyConfigPropertySourceLoader(); + this.propertySource = propertySourceLoader.load(GrailsNameUtils.getLogicalPropertyName(pluginClass.getSimpleName(), "GrailsPlugin") + "-" + PLUGIN_GROOVY, resource, null, DEFAULT_CONFIG_IGNORE_LIST); + } } catch (IOException e) { - LOG.warn("Error loading plugin.yml for plugin: " + pluginClass.getName() +": " + e.getMessage(), e); + LOG.warn("Error loading " + filename + " for plugin: " + pluginClass.getName() +": " + e.getMessage(), e); } } } @@ -113,15 +123,28 @@ public boolean isEnabled(String[] profiles) { } protected Resource readPluginConfiguration(Class pluginClass) { - final URL urlToPluginYml = IOUtils.findResourceRelativeToClass(pluginClass, PLUGIN_YML_PATH); + Resource ymlResource = getConfigurationResource(pluginClass, PLUGIN_YML_PATH); + Resource groovyResource = getConfigurationResource(pluginClass, PLUGIN_GROOVY_PATH); + + Boolean groovyResourceExists = groovyResource != null && groovyResource.exists(); - Resource urlResource = urlToPluginYml != null ? new UrlResource(urlToPluginYml) : null; - if(urlResource != null && urlResource.exists()) { - return urlResource; + if(ymlResource != null && ymlResource.exists()) { + if (groovyResourceExists) { + throw new RuntimeException("A plugin may define a plugin.yml or a plugin.groovy, but not both"); + } + return ymlResource; + } + if(groovyResourceExists) { + return groovyResource; } return null; } + protected Resource getConfigurationResource(Class pluginClass, String path) { + final URL urlToConfig = IOUtils.findResourceRelativeToClass(pluginClass, path); + return urlToConfig != null ? new UrlResource(urlToConfig) : null; + } + public String getFileSystemName() { return getFileSystemShortName() + '-' + getVersion(); } diff --git a/grails-core/src/test/groovy/org/codehaus/groovy/grails/plugins/BinaryPluginSpec.groovy b/grails-core/src/test/groovy/org/codehaus/groovy/grails/plugins/BinaryPluginSpec.groovy index e4495d9b16b..82a3f8df4f5 100644 --- a/grails-core/src/test/groovy/org/codehaus/groovy/grails/plugins/BinaryPluginSpec.groovy +++ b/grails-core/src/test/groovy/org/codehaus/groovy/grails/plugins/BinaryPluginSpec.groovy @@ -4,15 +4,15 @@ import grails.core.DefaultGrailsApplication import org.grails.plugins.BinaryGrailsPlugin import org.grails.plugins.BinaryGrailsPluginDescriptor import org.springframework.core.io.ByteArrayResource +import org.springframework.core.io.FileSystemResource import org.springframework.core.io.Resource - +import spock.lang.Shared import spock.lang.Specification class BinaryPluginSpec extends Specification { - def "Test creation of a binary plugin"() { - given: - def str = ''' + @Shared + String testBinary = ''' org.codehaus.groovy.grails.plugins.TestBinaryGrailsPlugin @@ -21,10 +21,9 @@ class BinaryPluginSpec extends Specification { ''' - def xml = new XmlSlurper().parseText(str) - + def "Test creation of a binary plugin"() { when: - def descriptor = new BinaryGrailsPluginDescriptor(new ByteArrayResource(str.getBytes('UTF-8')), ['org.codehaus.groovy.grails.plugins.TestBinaryResource']) + def descriptor = new BinaryGrailsPluginDescriptor(new ByteArrayResource(testBinary.getBytes('UTF-8')), ['org.codehaus.groovy.grails.plugins.TestBinaryResource']) def binaryPlugin = new BinaryGrailsPlugin(TestBinaryGrailsPlugin, descriptor, new DefaultGrailsApplication()) then: @@ -36,20 +35,8 @@ class BinaryPluginSpec extends Specification { def "Test load static resource from binary plugin"() { - given: - def str = ''' - - org.codehaus.groovy.grails.plugins.TestBinaryGrailsPlugin - - org.codehaus.groovy.grails.plugins.TestBinaryResource - - - ''' - - def xml = new XmlSlurper().parseText(str) - when: - def resource = new MockBinaryPluginResource(str.getBytes('UTF-8')) + def resource = new MockBinaryPluginResource(testBinary.getBytes('UTF-8')) def descriptor = new BinaryGrailsPluginDescriptor(resource, ['org.codehaus.groovy.grails.plugins.TestBinaryResource']) resource.relativesResources['static/css/main.css'] = new ByteArrayResource(''.bytes) def binaryPlugin = new BinaryGrailsPlugin(TestBinaryGrailsPlugin, descriptor, new DefaultGrailsApplication()) @@ -63,6 +50,68 @@ class BinaryPluginSpec extends Specification { then: cssResource == null } + + def "Test plugin with both plugin.yml and plugin.groovy throws exception"() { + when: + def descriptor = new BinaryGrailsPluginDescriptor(new ByteArrayResource(testBinary.getBytes('UTF-8')), ['org.codehaus.groovy.grails.plugins.TestBinaryResource']) + MockConfigBinaryGrailsPlugin.YAML_EXISTS = true + MockConfigBinaryGrailsPlugin.GROOVY_EXISTS = true + new MockConfigBinaryGrailsPlugin(descriptor) + + then: + thrown(RuntimeException) + } + + def "Test plugin with only plugin.yml"() { + when: + def descriptor = new BinaryGrailsPluginDescriptor(new ByteArrayResource(testBinary.getBytes('UTF-8')), ['org.codehaus.groovy.grails.plugins.TestBinaryResource']) + MockConfigBinaryGrailsPlugin.YAML_EXISTS = true + MockConfigBinaryGrailsPlugin.GROOVY_EXISTS = false + def binaryPlugin = new MockConfigBinaryGrailsPlugin(descriptor) + + then: + binaryPlugin.propertySource.getProperty('foo') == "bar" + } + + def "Test plugin with only plugin.groovy"() { + when: + def descriptor = new BinaryGrailsPluginDescriptor(new ByteArrayResource(testBinary.getBytes('UTF-8')), ['org.codehaus.groovy.grails.plugins.TestBinaryResource']) + MockConfigBinaryGrailsPlugin.YAML_EXISTS = false + MockConfigBinaryGrailsPlugin.GROOVY_EXISTS = true + def binaryPlugin = new MockConfigBinaryGrailsPlugin(descriptor) + + then: + binaryPlugin.propertySource.getProperty('bar') == "foo" + } + +} + +class MockConfigBinaryGrailsPlugin extends BinaryGrailsPlugin { + static Boolean YAML_EXISTS = false + static Boolean GROOVY_EXISTS = false + + MockConfigBinaryGrailsPlugin(BinaryGrailsPluginDescriptor descriptor) { + super(TestBinaryGrailsPlugin, descriptor, new DefaultGrailsApplication()) + } + + protected Resource getConfigurationResource(Class pluginClass, String path) { + String tempDir = System.getProperty("java.io.tmpdir") + if (YAML_EXISTS && path == PLUGIN_YML_PATH) { + File file = new File(tempDir, "plugin.yml") + file.write("foo: bar") + return new FileSystemResource(file) + } + if (GROOVY_EXISTS && path == PLUGIN_GROOVY_PATH) { + File file = new File(tempDir, "plugin.groovy") + file.write("bar = 'foo'") + return new FileSystemResource(file) + } + return null + } + + public String getVersion() { + super.getVersion() + } } class TestBinaryGrailsPlugin { @@ -91,3 +140,4 @@ class MyView extends Script { return "Good" } } + diff --git a/grails-gradle-plugin/src/main/groovy/org/grails/gradle/plugin/core/GrailsPluginGradlePlugin.groovy b/grails-gradle-plugin/src/main/groovy/org/grails/gradle/plugin/core/GrailsPluginGradlePlugin.groovy index 73fe1b30e94..0a62b0b3be3 100644 --- a/grails-gradle-plugin/src/main/groovy/org/grails/gradle/plugin/core/GrailsPluginGradlePlugin.groovy +++ b/grails-gradle-plugin/src/main/groovy/org/grails/gradle/plugin/core/GrailsPluginGradlePlugin.groovy @@ -56,6 +56,8 @@ class GrailsPluginGradlePlugin extends GrailsGradlePlugin { void apply(Project project) { super.apply(project) + checkForConfigurationClash(project) + configureAstSources(project) configureProjectNameAndVersionASTMetadata(project) @@ -237,6 +239,14 @@ withConfig(configuration) { } } + protected void checkForConfigurationClash(Project project) { + File yamlConfig = new File(project.projectDir,"grails-app/conf/plugin.yml") + File groovyConfig = new File(project.projectDir,"grails-app/conf/plugin.groovy") + if (yamlConfig.exists() && groovyConfig.exists()) { + throw new RuntimeException("A plugin may define a plugin.yml or a plugin.groovy, but not both") + } + } + @CompileStatic static class ExplodedDir implements PublishArtifact { final String extension = ""