@@ -27,6 +27,7 @@ import org.apache.ivy.core.module.descriptor.DependencyDescriptor
2727import org.apache.ivy.plugins.resolver.URLResolver
2828import org.apache.ivy.plugins.resolver.IBiblioResolver
2929import org.codehaus.groovy.grails.resolve.GrailsRepoResolver
30+ import org.springframework.util.AntPathMatcher
3031
3132/**
3233 * Generates the plugin.xml descriptor.
@@ -42,6 +43,7 @@ class PluginDescriptorGenerator {
4243 Resource [] resourceList
4344 List excludes = [" UrlMappings" , " DataSource" , " BuildConfig" , " Config" ]
4445 BuildSettings buildSettings
46+ AntPathMatcher antPathMatcher = new AntPathMatcher ()
4547
4648 PluginDescriptorGenerator (BuildSettings buildSettings , pluginName , List<Resource > resourceList ) {
4749 this . buildSettings = buildSettings
@@ -80,6 +82,53 @@ class PluginDescriptorGenerator {
8082 generatePluginXml(pluginProps, xml)
8183 }
8284
85+ /* the pluginExcludes are Ant matched from the base of the application, but since the
86+ pluginProps is not necessarily a class and we don't actually know where it is, we need
87+ to go through the resources figuring out what the common resource base is. We are going to assume
88+ a common Grails application layout to fudge this.
89+ */
90+ private String resourceBaseMatchDirs = [' grails-app' , ' web-app' , ' scripts' , ' test' , ' src' ]
91+ private File findCommonResourceBase () {
92+ if (! resourceList) return null // no resources, won't loop
93+
94+ for (Resource r in resourceList) {
95+ File f = r. file
96+
97+ while (f != null && ! resourceBaseMatchDirs. contains(f. name)) {
98+ f = f. parentFile
99+ }
100+
101+ if (f) {
102+ if (f. parentFile == null ) { // wonderful, thanks Resource
103+ return new File (f. absolutePath. substring(0 , f. absolutePath. lastIndexOf(File . separator)))
104+ } else {
105+ return f. parentFile
106+ }
107+ }
108+ }
109+
110+ GrailsUtil . warn(" Unable to determine common resource base when generating plugin.xml" )
111+
112+ return null
113+ }
114+
115+ private boolean matchesPluginExcludes (List<String > pluginExcludes , File commonResourceBase , Resource r ) {
116+
117+ // if we have no excludes or no common resource base, we don't match
118+ if (! pluginExcludes) return false
119+ if (! commonResourceBase) return false
120+
121+ if (r. file. absolutePath. indexOf(commonResourceBase. absolutePath) == 0 ) {
122+ String path = r. file. absolutePath. substring(commonResourceBase. absolutePath. length()+1 )
123+ for (String pattern : pluginExcludes) {
124+ if (antPathMatcher. match(pattern, path)) return true
125+ }
126+
127+ }
128+
129+ return false
130+ }
131+
83132 protected void generatePluginXml (pluginProps , MarkupBuilder xml ) {
84133 // Write the content!
85134 def props = [' author' , ' authorEmail' , ' title' , ' description' , ' documentation' , ' type' , ' packaging' ]
@@ -89,6 +138,13 @@ class PluginDescriptorGenerator {
89138
90139 def pluginGrailsVersion = " ${ GrailsUtil.grailsVersion} > *"
91140
141+ // check to see if we have the property, grab it if so
142+ def pluginExcludes
143+ if (pluginProps[' pluginExcludes' ])
144+ pluginExcludes = pluginProps. pluginExcludes
145+ else
146+ pluginExcludes = []
147+
92148 if (pluginProps != null ) {
93149 if (pluginProps[" grailsVersion" ]) {
94150 pluginGrailsVersion = pluginProps[" grailsVersion" ]
@@ -99,10 +155,12 @@ class PluginDescriptorGenerator {
99155 if (pluginProps[p]) " ${ p} " (pluginProps[p])
100156 }
101157 xml. resources {
158+ File commonResourceBase = findCommonResourceBase()
159+
102160 for (r in resourceList) {
103161 def matcher = r.URL . toString() =~ ARTEFACT_PATTERN
104162 def name = matcher[0 ][1 ]. replaceAll(' /' , / \. / )
105- if (! excludes. contains(name)) {
163+ if (! excludes. contains(name) && ! matchesPluginExcludes(pluginExcludes, commonResourceBase, r) ) {
106164 xml. resource(name)
107165 }
108166 }
0 commit comments