プラグインでコマンドを追加(Grails 0.5)

grails hoge-hoge とかすると、何かやってくれるようなコマンドをプラグインに追加したくって。例えば、grails configure-hogehoge とかすると、対話式にプラグインの設定ができるとか。
そりゃあ、多分できるのでしょう。なんといっても、開発者ガイドには、「コマンドラインインターフェイスからランタイムコンフィグレーションエンジンにいたるどんな拡張も可能にする方法を提供します」ですから。
さて、やってみる。まずはプラグインプロジェクトを。

grails create-plugin hoge

作成したプロジェクトのscriptsディレクトリに以下のHogeHoge.groovyを作成。

task ('default': "Print hoge message.") {
	println 'Hello from Grails plugin hoge'
}

これで完成。次にプラグインのZipファイルを作成。

cd hoge
grails package-plugin

パッケージ作成完了。あとは適当なGrailsプロジェクトでこのプラグインをインストールして、コマンドラインから

grails hoge-hoge

とすればOK。Hello from Grails plugin hoge って出力されます。なんて簡単なんだ。
でも、同じ名前があったらどうなるんだろう。AプラグインとBプラグインで同じコマンドがあった場合とか。
作ってみるのが手っ取り早いんだろうが、それも何なので、ソースをみた。grails.batで起動されているのは、org.codehaus.groovy.grails.cli.GrailsScriptRunnerだ。mainメソッド中に以下のような箇所が。

try {      
	callPluginOrGrailsScript(scriptName)
}
catch(Throwable t) {
	println "Error executing script ${scriptName}: ${t.message}"
	t.printStackTrace(System.out)
}

そのものずばりの名前。で、callPluginOrGrailsScript()はというと、

private static callPluginOrGrailsScript(scriptName) {
	def potentialScripts = [] 

	def userHome = ANT.antProject.properties."user.home"
		
	def scriptLocations = ["${baseDir.absolutePath}/scripts", "${grailsHome}/scripts", "${userHome}/.grails/scripts"]
	scriptLocations.each {
		def scriptFile = new File("${it}/${scriptName}.groovy")
		if(scriptFile.exists()) {
			potentialScripts << scriptFile
		}
	}
		                       
	try {
		def pluginScripts = RESOLVER.getResources("file:${baseDir.absolutePath}/plugins/**/scripts/${scriptName}.groovy")
		potentialScripts += pluginScripts.collect { it.file }			
	}
	catch(Exception e) {
		println "Note: No plugin scripts found"
	} 
	if(potentialScripts.size()>0) {  
		potentialScripts = potentialScripts.unique()
		if(potentialScripts.size() == 1) {
			println "Running script ${potentialScripts[0].absolutePath}"
                                                               
				Gant.main(["-c","-d","${userHome}/.grails/${version}/scriptCache","-f", potentialScripts[0].absolutePath] as String[])																		
		}                                      
		else {
			println "Multiple options please select:"  
			def validArgs = []
			potentialScripts.eachWithIndex { f, i ->
				println "[${i+1}] $f "
				validArgs << i+1
			}               
			ANT.input(message: "Enter # ",validargs:validArgs.join(","), addproperty:"grails.script.number")
                def number = ANT.antProject.properties."grails.script.number".toInteger()        

			println "Running script ${potentialScripts[number-1].absolutePath}"				
			Gant.main(["-f", potentialScripts[number-1].absolutePath] as String[])																						
		}
	}
	else {
		println "Script $scriptName not found."
	}    		
}

ほほう、複数あるときは、「Multiple options please select:」とかでて選択することになるっぽい。
これならどんな名前でも心配しなくていい。