GRAILS-1019: Allowing expressions to be used with the 'disabled' attribute for g...
[grails.git] / src / commons / org / codehaus / groovy / grails / cli / GrailsScriptRunner.groovy
bloba1772bd221d1653d07be7205d10ebafa4eeea858
1 /*
2 * Copyright 2004-2005 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.codehaus.groovy.grails.cli;
19 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU
21 import gant.Gant
22 import grails.util.GrailsUtil
23 import org.springframework.core.io.support.PathMatchingResourcePatternResolver
24 import org.codehaus.groovy.grails.commons.GrailsClassUtils
25 import org.codehaus.groovy.grails.commons.GrailsApplication
27 /**
28 * Class that handles Grails command line interface for running scripts
30 * @author Graeme Rocher
32 * @since 0.4
35 class GrailsScriptRunner {
36 static final ANT = new AntBuilder()
37 static final RESOLVER = new PathMatchingResourcePatternResolver()
39 static grailsHome
40 static baseDir
41 static userHome = System.properties.'user.home'
42 static version = GrailsUtil.getGrailsVersion()
43 static classesDir
44 static rootLoader
46 static main(String[] args) {
47 MetaClassRegistry registry = GroovySystem.metaClassRegistry
49 if(!(registry.getMetaClassCreationHandler() instanceof ExpandoMetaClassCreationHandle))
50 registry.setMetaClassCreationHandle(new ExpandoMetaClassCreationHandle());
52 ANT.property(environment:"env")
53 grailsHome = ANT.antProject.properties.'env.GRAILS_HOME'
55 if(!grailsHome) {
56 println "Environment variable GRAILS_HOME not set. Please set it to the location of your Grails installation and try again."
57 System.exit(0)
60 ANT.property(file:"${grailsHome}/build.properties")
61 def grailsVersion = ANT.antProject.properties.'grails.version'
63 println """
64 Welcome to Grails ${grailsVersion} - http://grails.org/
65 Licensed under Apache Standard License 2.0
66 Grails home is set to: ${grailsHome}
67 """
68 if(args.size() && args[0].trim()) {
71 baseDir = establishBaseDir()
72 println "Base Directory: ${baseDir.absolutePath}"
73 System.setProperty("base.dir", baseDir.absolutePath)
75 rootLoader = getClass().classLoader ? getClass().classLoader.rootLoader : Thread.currentThread().getContextClassLoader().rootLoader
76 def baseName = new File(baseDir.absolutePath).name
77 classesDir = new File("${userHome}/.grails/${grailsVersion}/projects/${baseName}/classes")
79 def allArgs = args[0].trim()
81 def scriptName = processArgumentsAndReturnScriptName(allArgs)
85 def scriptsAllowedOutsideProject = ['CreateApp','CreatePlugin','PackagePlugin','Help','ListPlugins','PluginInfo','SetProxy']
86 if(!new File(baseDir.absolutePath, "grails-app").exists() && (!scriptsAllowedOutsideProject.contains(scriptName))) {
87 println "${baseDir.absolutePath} does not appear to be part of a Grails application."
88 println 'The following commands are supported outside of a project:'
89 scriptsAllowedOutsideProject.sort().each {
90 println "\t${GCU.getScriptName(it)}"
92 println "Run 'grails help' for a complete list of available scripts."
93 println 'Exiting.'
94 System.exit(-1)
99 try {
100 if(scriptName.equalsIgnoreCase('interactive')) {
101 //disable exiting
102 System.metaClass.static.exit = { int code ->}
103 System.setProperty("grails.interactive.mode", "true")
104 int messageNumber = 0
105 while(true) {
106 println "--------------------------------------------------------"
107 ANT.input(message:"Interactive mode ready, type your command name in to continue (hit ENTER to run the last command):", addproperty:"grails.script.name${messageNumber}")
109 def enteredName = ANT.antProject.properties."grails.script.name${messageNumber++}"
110 if(enteredName) {
111 scriptName = processArgumentsAndReturnScriptName(enteredName)
113 def now = System.currentTimeMillis()
114 callPluginOrGrailsScript(scriptName)
115 def end = System.currentTimeMillis()
116 println "--------------------------------------------------------"
117 println "Command [$scriptName] completed in ${end-now}ms"
120 else {
121 System.exit(callPluginOrGrailsScript(scriptName))
126 catch(Throwable t) {
127 println "Error executing script ${scriptName}: ${t.message}"
128 t.printStackTrace(System.out)
129 System.exit(1)
133 else {
134 println "No script name specified. Use 'grails help' for more info or 'grails interactive' to enter interactive mode"
135 System.exit(0)
139 static processArgumentsAndReturnScriptName(allArgs) {
140 allArgs = processSystemArguments(allArgs).trim().split(" ")
141 def currentParamIndex = 0
142 if( isEnvironmentArgs(allArgs[currentParamIndex]) ) {
143 // use first argument as environment name and step further
144 calculateEnvironment(allArgs[currentParamIndex++])
145 } else {
146 // first argument is a script name so check for default environment
147 setDefaultEnvironment(allArgs[currentParamIndex])
150 if( currentParamIndex >= allArgs.size() ) {
151 println "You should specify a script to run. Run 'grails help' for a complete list of available scripts."
152 System.exit(0)
155 // use current argument as script name and step further
156 def paramName = allArgs[currentParamIndex++]
157 if (paramName[0] == '-') {
158 paramName = paramName[1..-1]
160 System.setProperty("current.gant.script", paramName)
161 def scriptName = GCU.getNameFromScript(paramName)
163 if( currentParamIndex < allArgs.size() ) {
164 // if we have additional params provided - store it in system property
165 System.setProperty("grails.cli.args", allArgs[currentParamIndex..-1].join("\n"))
167 return scriptName
170 static ENV_ARGS = [dev:GrailsApplication.ENV_DEVELOPMENT,prod:GrailsApplication.ENV_PRODUCTION,test:GrailsApplication.ENV_TEST]
171 // this map contains default environments for several scripts in form 'script-name':'env-code'
172 static DEFAULT_ENVS = ['war': GrailsApplication.ENV_PRODUCTION,'test-app':GrailsApplication.ENV_TEST,'run-webtest':GrailsApplication.ENV_TEST]
173 private static isEnvironmentArgs(env) {
174 ENV_ARGS.keySet().contains(env)
176 private static setDefaultEnvironment(args) {
177 if(!System.properties."${GrailsApplication.ENVIRONMENT}") {
178 def environment = DEFAULT_ENVS[args.toLowerCase()]
179 environment = environment ?: GrailsApplication.ENV_DEVELOPMENT
180 System.setProperty(GrailsApplication.ENVIRONMENT, environment )
181 System.setProperty(GrailsApplication.ENVIRONMENT_DEFAULT, "true")
184 private static calculateEnvironment(env) {
185 def environment = ENV_ARGS[env]
186 if( environment ) {
187 System.setProperty(GrailsApplication.ENVIRONMENT, environment)
188 } else {
189 setDefaultEnvironment("prod")
193 static SCRIPT_CACHE = [:]
194 static callPluginOrGrailsScript(scriptName) {
195 def potentialScripts
196 def binding
197 if(SCRIPT_CACHE[scriptName]) {
198 def cachedScript = SCRIPT_CACHE[scriptName]
199 potentialScripts = cachedScript.potentialScripts
200 binding = cachedScript.binding
202 else {
203 potentialScripts = []
204 def userHome = ANT.antProject.properties."user.home"
206 def scriptLocations = ["${baseDir.absolutePath}/scripts", "${grailsHome}/scripts", "${userHome}/.grails/scripts"]
207 scriptLocations.each {
208 def scriptFile = new File("${it}/${scriptName}.groovy")
209 if(scriptFile.exists()) {
210 potentialScripts << scriptFile
214 try {
215 def pluginScripts = RESOLVER.getResources("file:${baseDir.absolutePath}/plugins/*/scripts/${scriptName}.groovy")
216 potentialScripts += pluginScripts.collect { it.file }
218 catch(Exception e) {
219 println "Note: No plugin scripts found"
222 // Get the paths of any installed plugins and add them to the
223 // initial binding as '<pluginName>PluginDir'.
224 binding = new Binding()
225 try {
227 def plugins = RESOLVER.getResources("file:${baseDir.absolutePath}/plugins/*/*GrailsPlugin.groovy")
229 plugins.each { resource ->
230 def matcher = resource.filename =~ /(\S+)GrailsPlugin.groovy/
231 def pluginName = GrailsClassUtils.getPropertyName(matcher[0][1])
233 // Add the plugin path to the binding.
234 binding.setVariable("${pluginName}PluginDir", resource.file.parentFile)
237 catch(Exception e) {
238 // No plugins found.
240 SCRIPT_CACHE[scriptName] = new CachedScript(binding:binding, potentialScripts:potentialScripts)
245 if(potentialScripts.size()>0) {
246 potentialScripts = potentialScripts.unique()
247 if(potentialScripts.size() == 1) {
248 println "Running script ${potentialScripts[0].absolutePath}"
250 def gant = new Gant(binding, new URLClassLoader([classesDir.toURI().toURL()] as URL[], rootLoader))
251 return gant.processArgs(["-f", potentialScripts[0].absolutePath,"-c","-d","${userHome}/.grails/${version}/scriptCache"] as String[])
253 else {
254 println "Multiple options please select:"
255 def validArgs = []
256 potentialScripts.eachWithIndex { f, i ->
257 println "[${i+1}] $f "
258 validArgs << i+1
260 ANT.input(message: "Enter # ",validargs:validArgs.join(","), addproperty:"grails.script.number")
261 def number = ANT.antProject.properties."grails.script.number".toInteger()
263 println "Running script ${potentialScripts[number-1].absolutePath}"
264 def gant = new Gant(binding, new URLClassLoader([classesDir.toURI().toURL()] as URL[], rootLoader))
265 return gant.processArgs(["-f", potentialScripts[number-1].absolutePath] as String[])
268 else {
269 println "Script $scriptName not found."
270 println "Run 'grails help' for a complete list of available scripts."
271 return 0
275 private static processSystemArguments(allArgs) {
276 def lastMatch = null
277 allArgs.eachMatch( /-D(.+?)=(.+?)\s+?/ ) { match ->
278 System.setProperty(match[1].trim(),match[2].trim())
279 lastMatch = match[0]
282 if(lastMatch) {
283 def i = allArgs.lastIndexOf(lastMatch)+lastMatch.size()
284 allArgs = allArgs[i..-1]
286 return allArgs
289 private static establishBaseDir() {
290 def sysProp = System.getProperty("base.dir")
291 def baseDir
292 if(sysProp) {
293 baseDir = sysProp == '.' ? new File("") : new File(sysProp)
295 else {
296 baseDir = new File("")
297 if(!new File(baseDir.absolutePath, "grails-app").exists()) {
299 // be careful with this next step...
300 // baseDir.parentFile will return null since baseDir is new File("")
301 // baseDir.absoluteFile needs to happen before retrieving the parentFile
302 def parentDir = baseDir.absoluteFile.parentFile
304 // keep moving up one directory until we find
305 // one that contains the grails-app dir or get
306 // to the top of the filesystem...
307 while(parentDir != null && !new File(parentDir, "grails-app").exists()) {
308 parentDir = parentDir.parentFile
311 if(parentDir != null) {
312 // if we found the project root, use it
313 baseDir = parentDir
318 return baseDir
323 class CachedScript {
324 Binding binding
325 List potentialScripts