(Quick Reference)

4 命令行 - Reference Documentation

Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith

Version: null

4 命令行

Grails' command line system is built on Gant - a simple Groovy wrapper around Apache Ant.

However, Grails takes it further through the use of convention and the grails command. When you type:

grails [command name]

Grails searches in the following directories for Gant scripts to execute:

  • USER_HOME/.grails/scripts
  • PROJECT_HOME/scripts
  • PROJECT_HOME/plugins/*/scripts
  • GRAILS_HOME/scripts

Grails will also convert command names that are in lower case form such as run-app into camel case. So typing

grails run-app

Results in a search for the following files:

  • USER_HOME/.grails/scripts/RunApp.groovy
  • PROJECT_HOME/scripts/RunApp.groovy
  • PLUGINS_HOME/*/scripts/RunApp.groovy
  • GLOBAL_PLUGINS_HOME/*/scripts/RunApp.groovy
  • GRAILS_HOME/scripts/RunApp.groovy

If multiple matches are found Grails will give you a choice of which one to execute.

When Grails executes a Gant script, it invokes the "default" target defined in that script. If there is no default, Grails will quit with an error.

To get a list of all commands and some help about the available commands type:

grails help

which outputs usage instructions and the list of commands Grails is aware of:

Usage (optionals marked with *):
grails [environment]* [target] [arguments]*

Examples: grails dev run-app grails create-app books

Available Targets (type grails help 'target-name' for more info): grails bootstrap grails bug-report grails clean grails compile ...

Refer to the Command Line reference in the Quick Reference menu of the reference guide for more information about individual commands

It's often useful to provide custom arguments to the JVM when running Grails commands, in particular with run-app where you may for example want to set a higher maximum heap size. The Grails command will use any JVM options provided in the general JAVA_OPTS environment variable, but you can also specify a Grails-specific environment variable too:

export GRAILS_OPTS="-Xmx1G -Xms256m -XX:MaxPermSize=256m"
grails run-app
Grails的命令行系统建立在Gant之上 - 对Apache Ant进行了简单的包装.

然而,Grails通过约定规则以及grails命令的使用带来了一些改进。 当你键入如下内容时:

grails [命令名]

为了Gant脚本的执行,Grails会在下列目录中做一次搜索::

  • USER_HOME/.grails/scripts
  • PROJECT_HOME/scripts
  • PROJECT_HOME/plugins/*/scripts
  • GRAILS_HOME/scripts

Grails将把小写的命令名称(如run-app)转换为单词连写的格式。因此如果键入的是

grails run-app

Results in a search for the following files:

  • USER_HOME/.grails/scripts/RunApp.groovy
  • PROJECT_HOME/scripts/RunApp.groovy
  • PLUGINS_HOME/*/scripts/RunApp.groovy
  • GLOBAL_PLUGINS_HOME/*/scripts/RunApp.groovy
  • GRAILS_HOME/scripts/RunApp.groovy

如果找到多个同名的文件,Grails将要求你选择执行其中的一个。当Grails执行一个Gant脚本的时候,它会首先调用定义在脚本文件中的“default”任务。如果找不到“default”任务,Grails将退出并报错。

获得可用的命令及其帮助信息:

grails help

这个命令将输出Grails当前所知的命令列表和使用说明:

Usage (optionals marked with *):
grails [environment]* [target] [arguments]*

Examples: grails dev run-app grails create-app books

Available Targets (type grails help 'target-name' for more info): grails bootstrap grails bug-report grails clean grails compile ...

在快速参考菜单中,可以获得更多的命令行的信息。

当运行grails 命令的时候,提供自定义JVM的参数非常有用,尤其是run-app命令,例如,你可能想设置更大的JVM堆大小。Grails命令会使用环境变量JAVA_OPTS配置的所有JVM options,但你也可以指定一个Grails特定的环境变量:

export GRAILS_OPTS="-Xmx1G -Xms256m -XX:MaxPermSize=256m"
grails run-app

non-interactive mode

When you run a script manually and it prompts you for information, you can answer the questions and continue running the script. But when you run a script as part of an automated process, for example a continuous integration build server, there's no way to "answer" the questions. So you can pass the --non-interactive switch to the script command to tell Grails to accept the default answer for any questions, for example whether to install a missing plugin.

For example:

grails war --non-interactive

非交互模式

当你手动执行一个脚本并提示你输入信息,你可以回答问题并接续执行脚本。但是当作为一个自动化过程中的一部分运行脚本,例如持续集成构建服务器,就没有办法手动"回答"的问题了。这个时候,你可以通过--non-interactive开关来告诉Grails采用所有问题的默认回答,例如,是否要安装缺少的插件。

例如:

grails war --non-interactive

4.1 交互模式

交互模式是保持在JVM上运行,并允许更快地执行命令的Grails命令的功能。要激活交互模式可以再命令行中键入'Grails',然后使用Tab键补全获取命令列表:

如果你需要在交互模式中打开一个文件,你可以使用open命令和用TAB键完成文件路径:

更妙的是,open命令会识别'test-report' 和 'dep-report'这个两个逻辑别名,这将打开近期的测试和依赖报告。换句话说,在浏览器中打开测试报告仅需简单地执行open test-report命令。您甚至可以一次打开多个文件:open test-report test/unit/MyTests.groovy 将在您的浏览器打开的HTML测试报告和在你的文本编辑器中打开MyTests.groovy源文件。

create-*命令后面按TAB键补全完成类名同样是起作用的:

在交互模式中如果你需要运行一个外部进程,你可以用命令a !:

请注意你可以用! (bang)命令让文件路径自动完成 - 非常适合像'ls', 'cat', 'git'等操作文件系统的外部命令。

Interactive mode is the a feature of the Grails command line which keeps the JVM running and allows for quicker execution of commands. To activate interactive mode type 'grails' at the command line and then use TAB completion to get a list of commands:

If you need to open a file whilst within interactive mode you can use the open command which will TAB complete file paths:

Even better, the open command understands the logical aliases 'test-report' and 'dep-report', which will open the most recent test and dependency reports respectively. In other words, to open the test report in a browser simply execute open test-report. You can event open multiple files at once: open test-report test/unit/MyTests.groovy will open the HTML test report in your browser and the MyTests.groovy source file in your text editor.

TAB completion also works for class names after the create-* commands:

If you need to run an external process whilst interactive mode is running you can do so by starting the command with a !:

Note that with ! (bang) commands, you get file path auto completion - ideal for external commands that operate on the file system such as 'ls', 'cat', 'git', etc.

4.2 创建Gant脚本

你可以在项目的根目录下运行 create-script 命令来创建你自己的Gant脚本。例如如下命令:

grails create-script compile-sources

这将创建一个叫做 scripts/CompileSources.groovy 的脚本。Gant脚本本身与规范的Groovy脚本非常相似,除了它支持“targets”的概念以及它们之间的依赖关系:

target(default:"The default target is the one that gets executed by Grails") {
    depends(clean, compile)
}

target(clean:"Clean out things") { ant.delete(dir:"output") }

target(compile:"Compile some sources") { ant.mkdir(dir:"mkdir") ant.javac(srcdir:"src/java", destdir:"output") }

如上面的脚本所说明的,这个内置的 ant 变量(一个 groovy.util.AntBuilder 实例)可以访问 Apache Ant API

在以前的Grails中(1.0.3和以下),这个变量是 Ant,即第一个字母是大写的。

你也可以依赖其他的任务,只要在 default 任务中使用 depends 方法说明。

默认任务(default)

在上边的例子中,我们使用明确的名称“default”来指明一个任务。这是为一个脚本文件定义默认任务的一种方式。可选的另一种方式是使用 setDefaultTarget() 方法:

target("clean-compile": "Performs a clean compilation on the app source") {
    depends(clean, compile)
}

target(clean:"Clean out things") { ant.delete(dir:"output") }

target(compile:"Compile some sources") { ant.mkdir(dir:"mkdir") ant.javac(srcdir:"src/java", destdir:"output") }

setDefaultTarget("clean-compile")

这样将允许你从其他脚本中直接调用默认的任务。另外,尽管在这个例子中我们把调用 setDefaultTarget() 这一行放在了脚本文件的最后,但你可以把它放在任何位置,只要它位于它要引用的那个任务_之后_(在这个例子中这个任务就是“clean-compile”)。

哪种方式更好?坦率地说,你可以使用你喜欢的那种方式——看起来这两种方式都没有什么突出的优势。我们应该讨论的一个问题是,如果你想要允许任何其他脚本都能调用你的“default”任务,那么你应该把它移动到一个没有默认任务的共享脚本文件中。关于这些内容,我们将在下一章节进行更多讨论。

You can create your own Gant scripts by running the create-script command from the root of your project. For example the following command:

grails create-script compile-sources

Will create a script called scripts/CompileSources.groovy. A Gant script itself is similar to a regular Groovy script except that it supports the concept of "targets" and dependencies between them:

target(default:"The default target is the one that gets executed by Grails") {
    depends(clean, compile)
}

target(clean:"Clean out things") { ant.delete(dir:"output") }

target(compile:"Compile some sources") { ant.mkdir(dir:"mkdir") ant.javac(srcdir:"src/java", destdir:"output") }

As demonstrated in the script above, there is an implicit ant variable (an instance of groovy.util.AntBuilder) that allows access to the Apache Ant API.

In previous versions of Grails (1.0.3 and below), the variable was Ant, i.e. with a capital first letter.

You can also "depend" on other targets using the depends method demonstrated in the default target above.

The default target

In the example above, we specified a target with the explicit name "default". This is one way of defining the default target for a script. An alternative approach is to use the setDefaultTarget() method:

target("clean-compile": "Performs a clean compilation on the app source") {
    depends(clean, compile)
}

target(clean:"Clean out things") { ant.delete(dir:"output") }

target(compile:"Compile some sources") { ant.mkdir(dir:"mkdir") ant.javac(srcdir:"src/java", destdir:"output") }

setDefaultTarget("clean-compile")

This lets you call the default target directly from other scripts if you wish. Also, although we have put the call to setDefaultTarget() at the end of the script in this example, it can go anywhere as long as it comes after the target it refers to ("clean-compile" in this case).

Which approach is better? To be honest, you can use whichever you prefer - there don't seem to be any major advantages in either case. One thing we would say is that if you want to allow other scripts to call your "default" target, you should move it into a shared script that doesn't have a default target at all. We'll talk some more about this in the next section.

4.3 重用Grails脚本

Grails带了许多开箱即用的命令行功能,你会发现这在你自己的脚本中那个会很有用(查看参考指南的命令行指南部分可以获得所有命令的详细信息)。尤其是使用 compile, packagebootstrap 脚本。

下边的bootstrap脚本例子允许你启动一个Spring的 ApplicationContext 实例,通过它来访问数据源等(集成测试时可以这样用):

includeTargets << grailsScript("_GrailsBootstrap")

target ('default': "Database stuff") { depends(configureProxy, packageApp, classpath, loadApp, configureApp)

Connection c try { c = appCtx.getBean('dataSource').getConnection() // do something with connection } finally { c?.close() } }

从其他脚本文件引入任务

Gant允许你从另一个Gant脚本文件中引入所有任务(除了“default”)。然后你就可以depend或调用这些已经被定义在当前脚本文件中的任务了。实现的途径是includeTargets属性。使用左移操作符来简单的“附加”一个文件或类:
includeTargets << new File("/path/to/my/script.groovy")
includeTargets << gant.tools.Ivy
不用太担心关于使用一个类的语法,它是相当特殊的。要是你感兴趣,可以看看Gant的文档。

核心的Grails任务

如你在本章开头部分所看到的例子,当使用includeTargets来包含核心的Grails任务时,既没有使用基于文件的语法也没有使用基于类的语法。取而代之的,你应该使用Grails命令启动器提供的特殊的grailsScript()方法(注意这个方法在一般的Gant脚本中是不可用的,只有在Grails环境中才行)。

grailsScript() 方法的语法是非常简单易读的:简单的把你想要包含的Grails脚本文件的名称传入,不需要任何路径信息。以下是一个你可能想要重用的Grails脚本列表:

脚本描述
_GrailsSettings你确实应该包括这个!幸运的是,它已经被所有其他Grails脚本文件自动包括了(除了_GrailsProxy),因此你通常不必明确的包括它。
_GrailsEvents如果你想要触发事件,你应该包括这个。添加一个event(String eventName, List args)方法。另外,这也被几乎所有其他Grails脚本文件包括。
_GrailsClasspath安装编译、测试和运行用的classpath。如果你想使用它们,就包含这个脚本。另外,这也由几乎所有其他Grails脚本包含。
_GrailsProxy如果你不直接接入互联网,而是使用代理,包含这个脚本,配置代理参数。
_GrailsArgParsing提供一个parseArguments任务,就像字面上的意思:当运行你的脚本的时候解析用户提供的参数。把参数添加到argsMap属性中。
_GrailsTest包含所有共享的测试代码。如果你要添加额外的测试这将非常有用。
_GrailsRun为你提供在配置好的servlet容器中运行应用程序时需要的一切,可以是正常的运行(runApp/runAppHttps) ,也可以是来自于一个WAR文件(runWar/runWarHttps)。

这些由Grails提供的脚本很值得对它们进行深入的分析,从而找出哪些类型的任务是可以使用的。任何脚本文件都是以"_"作为前缀以便进行重用。

脚本结构

你可能对这些下划线词语作为Grails脚本的名称感到疑惑。用_internal_作为一个脚本或者用没有对应的“command”的其他单词,这些就是Grails的决定方式。因此无法运行例如"grails _grails-settings"这样的命令。这也就是为什么它们没有个默认的任务。

内部脚本是和代码共享重用相关的。实际上,我们建议在自己的脚本中使用类似的方式:把你的所有任务放入一个内部脚本中可以更容易的共享,然后提供简单的命令脚本来解析任何命令行参数并委托给内部脚本中的任务。假如你有一个脚本要运行一些功能测试——你可以将它们像这样分离:

./scripts/FunctionalTests.groovy:

includeTargets << new File("${basedir}/scripts/_FunctionalTests.groovy")

target(default: "Runs the functional tests for this project.") { depends(runFunctionalTests) }

./scripts/_FunctionalTests.groovy:

includeTargets << grailsScript("_GrailsTest")

target(runFunctionalTests: "Run functional tests.") { depends(...) … }

以下是在编写脚本时常用的一些指导方案:

  • 将脚本分为“command”脚本和内部脚本。
  • 将大部分执行脚本放入内部脚本。
  • 将参数解析放入“command”脚本。
  • 要把参数传入一个任务,先创建一些脚本变量并在调用任务前将它们初始化。
  • 为了避免名称冲突,可以为脚本变量分配闭包以替代任务。之后你可以直接将参数传入闭包。

Grails ships with a lot of command line functionality out of the box that you may find useful in your own scripts (See the command line reference in the reference guide for info on all the commands). Of particular use are the compile, package and bootstrap scripts.

The bootstrap script for example lets you bootstrap a Spring ApplicationContext instance to get access to the data source and so on (the integration tests use this):

includeTargets << grailsScript("_GrailsBootstrap")

target ('default': "Database stuff") { depends(configureProxy, packageApp, classpath, loadApp, configureApp)

Connection c try { c = appCtx.getBean('dataSource').getConnection() // do something with connection } finally { c?.close() } }

Pulling in targets from other scripts

Gant lets you pull in all targets (except "default") from another Gant script. You can then depend upon or invoke those targets as if they had been defined in the current script. The mechanism for doing this is the includeTargets property. Simply "append" a file or class to it using the left-shift operator:

includeTargets << new File("/path/to/my/script.groovy")
includeTargets << gant.tools.Ivy
Don't worry too much about the syntax using a class, it's quite specialised. If you're interested, look into the Gant documentation.

Core Grails targets

As you saw in the example at the beginning of this section, you use neither the File- nor the class-based syntax for includeTargets when including core Grails targets. Instead, you should use the special grailsScript() method that is provided by the Grails command launcher (note that this is not available in normal Gant scripts, just Grails ones).

The syntax for the grailsScript() method is pretty straightforward: simply pass it the name of the Grails script to include, without any path information. Here is a list of Grails scripts that you could reuse:

ScriptDescription
_GrailsSettingsYou really should include this! Fortunately, it is included automatically by all other Grails scripts except _GrailsProxy, so you usually don't have to include it explicitly.
_GrailsEventsInclude this to fire events. Adds an event(String eventName, List args) method. Again, included by almost all other Grails scripts.
_GrailsClasspathConfigures compilation, test, and runtime classpaths. If you want to use or play with them, include this script. Again, included by almost all other Grails scripts.
_GrailsProxyIf you don't have direct access to the internet and use a proxy, include this script to configure access through your proxy.
_GrailsArgParsingProvides a parseArguments target that does what it says on the tin: parses the arguments provided by the user when they run your script. Adds them to the argsMap property.
_GrailsTestContains all the shared test code. Useful if you want to add any extra tests.
_GrailsRunProvides all you need to run the application in the configured servlet container, either normally (runApp/runAppHttps) or from a WAR file (runWar/runWarHttps).

There are many more scripts provided by Grails, so it is worth digging into the scripts themselves to find out what kind of targets are available. Anything that starts with an "_" is designed for reuse.

Script architecture

You maybe wondering what those underscores are doing in the names of the Grails scripts. That is Grails' way of determining that a script is internal , or in other words that it has not corresponding "command". So you can't run "grails _grails-settings" for example. That is also why they don't have a default target.

Internal scripts are all about code sharing and reuse. In fact, we recommend you take a similar approach in your own scripts: put all your targets into an internal script that can be easily shared, and provide simple command scripts that parse any command line arguments and delegate to the targets in the internal script. For example if you have a script that runs some functional tests, you can split it like this:

./scripts/FunctionalTests.groovy:

includeTargets << new File("${basedir}/scripts/_FunctionalTests.groovy")

target(default: "Runs the functional tests for this project.") { depends(runFunctionalTests) }

./scripts/_FunctionalTests.groovy:

includeTargets << grailsScript("_GrailsTest")

target(runFunctionalTests: "Run functional tests.") { depends(...) … }

Here are a few general guidelines on writing scripts:

  • Split scripts into a "command" script and an internal one.
  • Put the bulk of the implementation in the internal script.
  • Put argument parsing into the "command" script.
  • To pass arguments to a target, create some script variables and initialise them before calling the target.
  • Avoid name clashes by using closures assigned to script variables instead of targets. You can then pass arguments direct to the closures.

4.4 钩子事件

Grails提供了钩住脚本事件的能力。这里指的是当Grails的任务和插件脚本执行的时候能触发的一些事件。

这个机制是故意简单化和松散的规定的。可能的事件列表是不会以任何方式固定的,所以可以钩住那些被插件脚本触发的事件,在核心目标脚本中没有类似的事件。

定义事件处理器

事件处理器是定义在称为 _Events.groovy 的脚本文件中。Grails会在以下位置搜索这些脚本:

  • USER_HOME/.grails/scripts - 用户特定的事件处理器
  • PROJECT_HOME/scripts - 应用程序特定的事件处理器
  • PLUGINS_HOME/*/scripts - 插件特定的事件处理器
  • GLOBAL_PLUGINS_HOME/*/scripts - 由全局插件提供的事件处理器

无论事件在何时被激发, 所有 已经注册到该事件的处理器都会被执行。需要注意的是处理器的注册工作会由Grails自动进行,你只需要在相关的 _Events.groovy 文件中声明即可。

事件处理器是分块定义在 _Events.groovy 文件中,使用“event”作为名称的开头部分。下边的例子可以被放在你的 /scripts 目录中来展示这个特性:

eventCreatedArtefact = { type, name ->
   println "Created $type $name"
}

eventStatusUpdate = { msg -> println msg }

eventStatusFinal = { msg -> println msg }

你可以看到这儿有三个处理器分别是:eventCreatedArtefact, eventStatusUpdate, eventStatusFinal。Grails提供了一些标准的事件,它们在命令行参考指南中有描述。例如compile命令会激发下列事件:

  • CompileStart - 当编译过程开始时,针对这几种类型的编译——源文件和测试文件
  • CompileEnd - 当编译过程完成时,针对这几种类型的编译——源文件和测试文件

触发事件

要简单地触发一个包含Init.groovy脚本的事件并调用event()闭包:

includeTargets << grailsScript("_GrailsEvents")

event("StatusFinal", ["Super duper plugin action complete!"])

公共事件

下表是一些可以被利用的公共事件:

事件参数描述
StatusUpdatemessage传入一个标志当前脚本状态或进展的字符串
StatusErrormessage传入一个标志来自当前脚本的错误信息的字符串
StatusFinalmessage传入一个标志最终脚本状态消息的字符串,例如:当编译一个任务时,即使任务还没有退出脚本环境
CreatedArtefactartefactType,artefactName当一个 create-xxxx 脚本已执行完成并创建了一个工件时调用
CreatedFilefileName当一个项目的源码文件被创建时调用,但不包括那些由Grails管理的固定文件
ExitingreturnCode当脚本环境即将正常的退出时调用
PluginInstalledpluginName在一个插件被安装之后调用
CompileStartkind当编译过程开始时调用,针对这几种类型的编译——源文件和测试文件
CompileEndkind当编译过程完成时调用,针对这几种类型的编译——源文件和测试文件
DocStartkind当生成文档过程即将开始时调用——生成javadoc或groovydoc时
DocEndkind当生成文档过程已经结束时调用——生成javadoc或groovydoc时
SetClasspathrootLoader在classpath初始化时调用以便插件可以通过 rootLoader.addURL(...)来扩大classpath。注意这种扩大classpath是在事件脚本被加载之后进行的,因此你不能使用这种方式来加载你的事件脚本需要导入的类,即使你可以通过名称来加载类。
PackagingEndnone当打包结束时调用(这个调用是在Tomcat服务器被启动之前并在web.xml文件被生成之后)

Grails provides the ability to hook into scripting events. These are events triggered during execution of Grails target and plugin scripts.

The mechanism is deliberately simple and loosely specified. The list of possible events is not fixed in any way, so it is possible to hook into events triggered by plugin scripts, for which there is no equivalent event in the core target scripts.

Defining event handlers

Event handlers are defined in scripts called _Events.groovy. Grails searches for these scripts in the following locations:

  • USER_HOME/.grails/scripts - user-specific event handlers
  • PROJECT_HOME/scripts - applicaton-specific event handlers
  • PLUGINS_HOME/*/scripts - plugin-specific event handlers
  • GLOBAL_PLUGINS_HOME/*/scripts - event handlers provided by global plugins

Whenever an event is fired, all the registered handlers for that event are executed. Note that the registration of handlers is performed automatically by Grails, so you just need to declare them in the relevant _Events.groovy file.

Event handlers are blocks defined in _Events.groovy, with a name beginning with "event". The following example can be put in your /scripts directory to demonstrate the feature:

eventCreatedArtefact = { type, name ->
   println "Created $type $name"
}

eventStatusUpdate = { msg -> println msg }

eventStatusFinal = { msg -> println msg }

You can see here the three handlers eventCreatedArtefact, eventStatusUpdate, eventStatusFinal. Grails provides some standard events, which are documented in the command line reference guide. For example the compile command fires the following events:

  • CompileStart - Called when compilation starts, passing the kind of compile - source or tests
  • CompileEnd - Called when compilation is finished, passing the kind of compile - source or tests

Triggering events

To trigger an event simply include the Init.groovy script and call the event() closure:

includeTargets << grailsScript("_GrailsEvents")

event("StatusFinal", ["Super duper plugin action complete!"])

Common Events

Below is a table of some of the common events that can be leveraged:

EventParametersDescription
StatusUpdatemessagePassed a string indicating current script status/progress
StatusErrormessagePassed a string indicating an error message from the current script
StatusFinalmessagePassed a string indicating the final script status message, i.e. when completing a target, even if the target does not exit the scripting environment
CreatedArtefactartefactType,artefactNameCalled when a create-xxxx script has completed and created an artefact
CreatedFilefileNameCalled whenever a project source filed is created, not including files constantly managed by Grails
ExitingreturnCodeCalled when the scripting environment is about to exit cleanly
PluginInstalledpluginNameCalled after a plugin has been installed
CompileStartkindCalled when compilation starts, passing the kind of compile - source or tests
CompileEndkindCalled when compilation is finished, passing the kind of compile - source or tests
DocStartkindCalled when documentation generation is about to start - javadoc or groovydoc
DocEndkindCalled when documentation generation has ended - javadoc or groovydoc
SetClasspathrootLoaderCalled during classpath initialization so plugins can augment the classpath with rootLoader.addURL(...). Note that this augments the classpath after event scripts are loaded so you cannot use this to load a class that your event script needs to import, although you can do this if you load the class by name.
PackagingEndnoneCalled at the end of packaging (which is called prior to the Tomcat server being started and after web.xml is generated)

4.5 自定义构建

Grails无疑是一个固执己见框架,并且它喜欢按照约定来进行配置,但这并不意味着你 不能 去配置它。在本章,我们将看到你可以如何去影响和修改标准的Grails构建。
Grails is most definitely an opinionated framework and it prefers convention to configuration, but this doesn't mean you can't configure it. In this section, we look at how you can influence and modify the standard Grails build.

默认

Grails构建配置的核心就是 grails.util.BuildSettings 类,它包含了大量有用的信息。它控制了哪些类被编译、应用程序依赖什么以及其他类似的设置。

以下是一个配置选项和它们的默认值的集录:

属性配置选项默认值
grailsWorkDirgrails.work.dir$USER_HOME/.grails/<grailsVersion>
projectWorkDirgrails.project.work.dir<grailsWorkDir>/projects/<baseDirName>
classesDirgrails.project.class.dir<projectWorkDir>/classes
testClassesDirgrails.project.test.class.dir<projectWorkDir>/test-classes
testReportsDirgrails.project.test.reports.dir<projectWorkDir>/test/reports
resourcesDirgrails.project.resource.dir<projectWorkDir>/resources
projectPluginsDirgrails.project.plugins.dir<projectWorkDir>/plugins
globalPluginsDirgrails.global.plugins.dir<grailsWorkDir>/global-plugins
verboseCompilegrails.project.compile.verbosefalse

BuildSettings 类也有一些其他属性,但是它们应该被只读处理:

属性描述
baseDir项目的位置。
userHome用户的主目录。
grailsHome正在使用的Grails的安装位置(也许为null)。
grailsVersion被项目使用的Grails的版本。
grailsEnv当前的Grails环境。
compileDependencies编译时项目依赖的文件实例列表。
testDependencies测试时项目依赖的文件实例列表。
runtimeDependencies运行时项目依赖的文件实例列表。

当然,如果你不能获得这些属性那么它们并没有多好。幸运的是这很容易实现:通过grailsSettings脚本变量可以得到一个BuildSettings实例用于你的脚本。你也可以在你的代码中通过使用grails.util.BuildSettingsHolder类来访问它,但是并不推荐这样做。

The defaults

The core of the Grails build configuration is the grails.util.BuildSettings class, which contains quite a bit of useful information. It controls where classes are compiled to, what dependencies the application has, and other such settings.

Here is a selection of the configuration options and their default values:

PropertyConfig optionDefault value
grailsWorkDirgrails.work.dir$USER_HOME/.grails/<grailsVersion>
projectWorkDirgrails.project.work.dir<grailsWorkDir>/projects/<baseDirName>
classesDirgrails.project.class.dir<projectWorkDir>/classes
testClassesDirgrails.project.test.class.dir<projectWorkDir>/test-classes
testReportsDirgrails.project.test.reports.dir<projectWorkDir>/test/reports
resourcesDirgrails.project.resource.dir<projectWorkDir>/resources
projectPluginsDirgrails.project.plugins.dir<projectWorkDir>/plugins
globalPluginsDirgrails.global.plugins.dir<grailsWorkDir>/global-plugins
verboseCompilegrails.project.compile.verbosefalse

The BuildSettings class has some other properties too, but they should be treated as read-only:

PropertyDescription
baseDirThe location of the project.
userHomeThe user's home directory.
grailsHomeThe location of the Grails installation in use (may be null).
grailsVersionThe version of Grails being used by the project.
grailsEnvThe current Grails environment.
compileDependenciesA list of compile-time project dependencies as File instances.
testDependenciesA list of test-time project dependencies as File instances.
runtimeDependenciesA list of runtime-time project dependencies as File instances.

Of course, these properties aren't much good if you can't get hold of them. Fortunately that's easy to do: an instance of BuildSettings is available to your scripts as the grailsSettings script variable. You can also access it from your code by using the grails.util.BuildSettingsHolder class, but this isn't recommended.

覆盖默认值

所有在第一个表中的属性都可以被一个系统属性或配置选项所覆盖——简单地使用“config option”名称。例如,要改变项目工作目录,你可以运行这个命令:

grails -Dgrails.project.work.dir=work compile
或者将这个选项添加到你的 grails-app/conf/BuildConfig.groovy 文件中:
grails.project.work.dir = "work"
注意默认值带有许多它们依赖的属性值,因此像这样设置项目工作目录也将迁移编译好的类、测试类、资源和插件。

如果你同时使用系统属性和配置选项将发生什么?当然是系统属性被采用了,因为它优先于BuildConfig.groovy 文件,而后者优先于默认值。

BuildConfig.groovy 文件是 grails-app/conf/Config.groovy 的姐妹文件,——过去包含的选项仅仅影响构建,但是之后包含的就影响正在运行的应用程序了。这并不局限于第一个表中的选项:你会发现构建配置选项在文档中到处都是,比如其中一些就用来指定内嵌的servlet容器应该运行在哪个端口上或者决定哪些文件应该被打包到WAR文件中。

可用的构建设置

名称描述
grails.server.port.http指定内嵌的servlet容器应该运行的端口(“run-app”和“run-war”命令使用)。整型。
grails.server.port.https指定内嵌的servlet容器用于HTTPS的运行端口 ("run-app --https" and "run-war --https"). 整型.
grails.config.base.webXml指定用于应用程序的自定义web.xml文件的路径(取代使用web.xml模板)。
grails.compiler.dependencies将额外的依赖添加到编译器classpath的传统方式。设置它到一个包含“fileset()”入口的闭包。 这些入口将被一个AntBuilder处理,所以这些入口的语法是以Groovy的形式出现,对应着Ant构建文件的XML元素,例如: fileset(dir: "$basedir/lib", include: "**/*.class).
grails.testing.patterns一个Ant路径格式的列表,允许你控制哪些文件可以被包含在测试中。这些格式不应该包括测试用例后缀,它们将在下一个属性中设置。
grails.testing.nameSuffix默认的,测试类都假定有一个“Tests”的后缀。你可以设置这个选项来改变它为你想要的任何内容。例如:另一个公共后缀是“Test”。
grails.project.war.file一个包含了生成的WAR文件的文件路径的字符串,除了它的全名意外(包括扩展名)。例如,“target/my-app.war”。
grails.war.dependencies一个包含“fileset()”入口的闭包,它允许你完全控制什么内容可以被放入WAR文件的“WEB-INF/lib”目录中。
grails.war.copyToWebApp一个包含“fileset()”入口的闭包,它允许你完全控制什么内容可以被放入WAR文件的根目录中。它覆盖了包含“web-app”目录下所有内容的那种默认习惯。
grails.war.resources一个闭包,用临时目录的地址作为它的第一个参数。你可以使用任何Ant任务来做你想做的任何事。这通常用来在临时目录被打包成WAR之前从中删除文件。
grails.project.web.xml生成Grails的web.xml的位置

Overriding the defaults

All of the properties in the first table can be overridden by a system property or a configuration option - simply use the "config option" name. For example, to change the project working directory, you could either run this command:

grails -Dgrails.project.work.dir=work compile
or add this option to your grails-app/conf/BuildConfig.groovy file:
grails.project.work.dir = "work"
Note that the default values take account of the property values they depend on, so setting the project working directory like this would also relocate the compiled classes, test classes, resources, and plugins.

What happens if you use both a system property and a configuration option? Then the system property wins because it takes precedence over the BuildConfig.groovy file, which in turn takes precedence over the default values.

The BuildConfig.groovy file is a sibling of grails-app/conf/Config.groovy - the former contains options that only affect the build, whereas the latter contains those that affect the application at runtime. It's not limited to the options in the first table either: you will find build configuration options dotted around the documentation, such as ones for specifying the port that the embedded servlet container runs on or for determining what files get packaged in the WAR file.

Available build settings

NameDescription
grails.server.port.httpPort to run the embedded servlet container on ("run-app" and "run-war"). Integer.
grails.server.port.httpsPort to run the embedded servlet container on for HTTPS ("run-app --https" and "run-war --https"). Integer.
grails.config.base.webXmlPath to a custom web.xml file to use for the application (alternative to using the web.xml template).
grails.compiler.dependenciesLegacy approach to adding extra dependencies to the compiler classpath. Set it to a closure containing "fileset()" entries. These entries will be processed by an AntBuilder so the syntax is the Groovy form of the corresponding XML elements in an Ant build file, e.g. fileset(dir: "$basedir/lib", include: "**/*.class).
grails.testing.patternsA list of Ant path patterns that let you control which files are included in the tests. The patterns should not include the test case suffix, which is set by the next property.
grails.testing.nameSuffixBy default, tests are assumed to have a suffix of "Tests". You can change it to anything you like but setting this option. For example, another common suffix is "Test".
grails.project.war.fileA string containing the file path of the generated WAR file, along with its full name (include extension). For example, "target/my-app.war".
grails.war.dependenciesA closure containing "fileset()" entries that allows you complete control over what goes in the WAR's "WEB-INF/lib" directory.
grails.war.copyToWebAppA closure containing "fileset()" entries that allows you complete control over what goes in the root of the WAR. It overrides the default behaviour of including everything under "web-app".
grails.war.resourcesA closure that takes the location of the staging directory as its first argument. You can use any Ant tasks to do anything you like. It is typically used to remove files from the staging directory before that directory is jar'd up into a WAR.
grails.project.web.xmlThe location to generate Grails' web.xml to

4.6 Ant和Maven

如果你的团队或公司的所有其他项目都在使用像Ant或Maven这样的标准的构建工具进行构建的,而你使用Grails命令行来构建你的应用程序时你就可能成为团队或者公司这个大家庭的害群之马。幸运的是,今天你可以很容易的将Grails构建系统集成到当今主流的构建工具中(嗯,至少是在Java项目中使用的那种构建工具)。

Ant 整合

当你通过 create-app 命令来创建一个Grails应用程序时,Grails不会自动创建Apache Ant 工具使用的build.xml文件,但是你可以通过integrate-with 命令来生成一个:

grails integrate-with --ant

这个命令会创建一个 build.xml 文件,这个文件包含了下列的任务:

  • clean - 清理Grails应用程序
  • compile - -编译你的应用程序的源码
  • test - 运行单元测试
  • run - 等同于“grails run-app”的功能
  • war - 创建一个WAR文件
  • deploy - 默认为空,但可以用它实现自动部署

这些任务都可以被Ant运行,例如:

ant war

为了实现依赖管理,构建文件已经被全面改进为使用 Apache Ivy for dependency management,这意味着它可以自动下载所有需要的Grails JAR文件和其他以来的文件。你甚至不必在本地安装Grails就可以使用它了!这对于需要使用像CruiseControl 或者 Jenkins这样的持续集成系统进行自动构建时特别有用。

这里使用了Grails的Ant task来对现有的Grails构建系统进行钩子操作。这个任务允许你运行任何可用的Grails脚本,不只是由生成的构建文件所使用的那些。要使用某个任务,你必须先声明它:

<taskdef name="grailsTask"
         classname="grails.ant.GrailsTask"
         classpathref="grails.classpath"/>

这也引出了另外的问题:“grails.classpath”中应该是什么内容?这个任务本身是在“grails-bootstrap”这个JAR工件中的,因此至少grails-bootstrap-xxx.jar需要在classpath中。同时也应该包含“groovy-all”这个JAR。对于这个任务定义,你只需要使用它!下表列出了可用的属性:

属性描述是否必填
home构建时需要用到的Grails安装目录的位置。除非classpath被指定否则必填。
classpathref载入Grails的Classpath。必须包含“grails-bootstrap”工件并且应该包含“grails-scripts”。除非home被设置或者你使用classpath元素否则必填。
script要运行的Grails脚本的名称,例如:“TestApp”。必填。
args要加入脚本中的参数,例如:“-unit -xml”。不是必填。默认为“”。
environment运行脚本时的Grails环境。不是必填。默认为脚本的default。
includeRuntimeClasspath高级设置:如果设为true则将应用程序的运行时classpath添加到构建classpath中。不是必填。默认为true

这个任务也支持下列内嵌元素,这些全都是标准的Ant路径结构:

  • classpath - 构建classpath(用来载入Gant和Grails脚本)。
  • compileClasspath - 用来编译应用程序的类的Classpath。
  • runtimeClasspath - 用来运行应用程序并将程序打成WAR包的Classpath。通常包含了compileClasspath中的一切。
  • testClasspath - 用来编译和运行测试的Classpath。通常包含了runtimeClasspath中的一切。.

要如何填写这些路径信息完全取决于你。如果你正在使用 home 属性并且把你自己的依赖内容放在了 lib 目录中,那么你不需要使用以上任何一个路径。如果想看看使用它们的例子,那么就查看为一个新应用而生成的Ant构建文件吧。

Maven集成

Grails通过一个Maven插件提供了与 Maven 2 的集成 .当前作为基础的Maven插件,特别是由 Octo 创建的这个版本是非常有效的,它做得非常出色。

准备

In order to use the new plugin, all you need is Maven 2 installed and set up. This is because you no longer need to install Grails separately to use it with Maven! 为了使用这个新的插件,你只需要安装和设置Maven 2。你不再需要单独的安装Grails!

Grails集成Maven 2已经针对Maven 2.0.9及以上版本进行了设计和测试。它将无法工作在更早期的版本中。

The default mvn setup DOES NOT supply sufficient memory to run the Grails environment. We recommend that you add the following environment variable setting to prevent poor performance: 默认的mvn设置没有配置充足的内存来运行grails环境。我们推荐你添加下面的环境变量防止系统表现不佳。

export MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=256"

创建一个 Grails Maven 项目

要简单地创建一个支持Maven的Grails项目只要运行下边的命令:

mvn archetype:generate -DarchetypeGroupId=org.grails \
    -DarchetypeArtifactId=grails-maven-archetype \
    -DarchetypeVersion=1.3.2 \
    -DgroupId=example -DartifactId=my-app

无论你想为你的应用选择哪个grails version,group ID和artifact ID,一切内容格式都必须像上面写的那样。这将创建一个新的Maven项目以及一个POM文件和一系列其他文件。你不会看到有什么是像一个Grails应用。因此,下一步就要创建一个你要使用的项目结构了。 但首先, 为了配置目标 JDK 为 Java 6, 打开 my-app/pom.xml 并且更新

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.5</source>
    <target>1.5</target>
  </configuration>
</plugin>
<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.6</source>
    <target>1.6</target>
  </configuration>
</plugin>

然后您就可以创建项目结构:

cd my-app
mvn initialize

如果你遇到下面类似的消息:

Resolving plugin JAR dependencies …
:: problems summary ::
:::: WARNINGS
        module not found: org.hibernate#hibernate-core;3.3.1.GA

你需要手动增加这个插件到 application.properties:

plugins.hibernate=2.0.0
plugins.tomcat=2.0.0

then run

mvn compile

最后 hibernate 和 tomcat 插件 会被安装。

现在你已经有一个可以使用的Grails应用了。插件已经集成到了标准的构建周期,因此你可以使用标准的Maven语法来构建和打包你的应用程序了: mvn clean , mvn compile , mvn test , mvn package , mvn install

你也可以利用许多已经被包装成Maven目标的Grails命令:

你可以调用 mvn grails:help 来获取一个完整的,最新的命令列表

给现有项目加入Maven支持

创建一个全新的项目当然是一个很好的途径,但如果已经有一个项目了该怎么办呢?你应该不会愿意先创建一个新项目然后再把旧项目的内容拷贝进去的。解决方法是使用下列命令为现有项目创建一个POM文件(以现有项目的Grails版本号代替下面的版本号):

mvn org.grails:grails-maven-plugin:1.3.2:create-pom -DgroupId=com.mycompany
当这个命令完成时,你就可以立即使用标准的语法了,如 mvn package 。需要注意的是当创建POM文件时你必须指定一个group ID。

你也可能想要设置目标JDK为Java 6,请看上面

添加Grails命令到 phase 中

标准的POM文件被创建是为了让Grails将合适的核心Grails命令附加到它们对应的构建语法上,因此“compile”对应“compile”语法,“war”对应“package”语法。当你想要将一个插件的命令附加到一个特定的phase上时,这可能没有什么帮助。典型的例子是功能测试。你如何确保你的功能测试(无论正在使用你决定的哪个插件)是使用“integration-test” phase来运行的?

恐怕不是:所有事情都是可能的。在这个例子中,你可以使用额外的“execution”块来将命令联合到一个 phase 上:

<plugin>
    <groupId>org.grails</groupId>
    <artifactId>grails-maven-plugin</artifactId>
    <version>1.3.2</version>
    <extensions>true</extensions>
    <executions>
        <execution>
            <goals></goals>
        </execution>
        <!-- 添加 "functional-tests" 命令到 "integration-test" phase -->
        <execution>
            <id>functional-tests</id>
            <phase>integration-test</phase>
            <goals>
                <goal>exec</goal>
            </goals>
            <configuration>
                <command>functional-tests</command>
            </configuration>
        </execution>
    </executions>
</plugin>

这也展示了 grails:exec 目标,它可以用来运行任何Grails命令。简单的将命令的名字作为 command 系统特性,还可以通过 args 特性来选择性地指定参数:

mvn grails:exec -Dcommand=create-webtest -Dargs=Book

调试一个 Grails Maven 工程

Maven可以使用“mvnDebug”命令在调试模式下启动。要启动调试你的Grails应用程序,只需运行:

mvnDebug grails:run-app

这一过程在启动的时候将被暂停和监听8000端口的调试器 The process will be suspended on startup and listening for a debugger on port 8000.

如果您需要更多的控制调试器,这可以使用的MAVEN_OPTS环境变量指定,并用默认的“MVN”命令来启动Maven:

MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"
mvn grails:run-app

提出问题

如果你遇到任何与Maven的集成的问题,请作为一个子任务提出一个JIRA问题GRAILS-3547.

If all the other projects in your team or company are built using a standard build tool such as Ant or Maven, you become the black sheep of the family when you use the Grails command line to build your application. Fortunately, you can easily integrate the Grails build system into the main build tools in use today (well, the ones in use in Java projects at least).

Ant Integration

When you create a Grails application with the create-app command, Grails doesn't automatically create an Ant build.xml file but you can generate one with the integrate-with command:


grails integrate-with --ant

This creates a build.xml file containing the following targets:

  • clean - Cleans the Grails application
  • compile - Compiles your application's source code
  • test - Runs the unit tests
  • run - Equivalent to "grails run-app"
  • war - Creates a WAR file
  • deploy - Empty by default, but can be used to implement automatic deployment

Each of these can be run by Ant, for example:

ant war

The build file is configured to use Apache Ivy for dependency management, which means that it will automatically download all the requisite Grails JAR files and other dependencies on demand. You don't even have to install Grails locally to use it! That makes it particularly useful for continuous integration systems such as CruiseControl or Jenkins.

It uses the Grails Ant task to hook into the existing Grails build system. The task lets you run any Grails script that's available, not just the ones used by the generated build file. To use the task, you must first declare it:

<taskdef name="grailsTask"
         classname="grails.ant.GrailsTask"
         classpathref="grails.classpath"/>

This raises the question: what should be in "grails.classpath"? The task itself is in the "grails-bootstrap" JAR artifact, so that needs to be on the classpath at least. You should also include the "groovy-all" JAR. With the task defined, you just need to use it! The following table shows you what attributes are available:

AttributeDescriptionRequired
homeThe location of the Grails installation directory to use for the build.Yes, unless classpath is specified.
classpathrefClasspath to load Grails from. Must include the "grails-bootstrap" artifact and should include "grails-scripts".Yes, unless home is set or you use a classpath element.
scriptThe name of the Grails script to run, e.g. "TestApp".Yes.
argsThe arguments to pass to the script, e.g. "-unit -xml".No. Defaults to "".
environmentThe Grails environment to run the script in.No. Defaults to the script default.
includeRuntimeClasspathAdvanced setting: adds the application's runtime classpath to the build classpath if true.No. Defaults to true.

The task also supports the following nested elements, all of which are standard Ant path structures:

  • classpath - The build classpath (used to load Gant and the Grails scripts).
  • compileClasspath - Classpath used to compile the application's classes.
  • runtimeClasspath - Classpath used to run the application and package the WAR. Typically includes everything in @compileClasspath.
  • testClasspath - Classpath used to compile and run the tests. Typically includes everything in runtimeClasspath.

How you populate these paths is up to you. If you use the home attribute and put your own dependencies in the lib directory, then you don't even need to use any of them. For an example of their use, take a look at the generated Ant build file for new apps.

Maven Integration

Grails provides integration with Maven 2 with a Maven plugin. The current Maven plugin is based on but supersedes the version created by Octo, who did a great job with the original.

Preparation

In order to use the new plugin, all you need is Maven 2 installed and set up. This is because you no longer need to install Grails separately to use it with Maven!

The Maven 2 integration for Grails has been designed and tested for Maven 2.0.9 and above. It will not work with earlier versions.

The default mvn setup DOES NOT supply sufficient memory to run the Grails environment. We recommend that you add the following environment variable setting to prevent poor performance:

export MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=256"

Creating a Grails Maven Project

To create a Mavenized Grails project simply run the following command:

mvn archetype:generate -DarchetypeGroupId=org.grails \
    -DarchetypeArtifactId=grails-maven-archetype \
    -DarchetypeVersion=1.3.2 \
    -DgroupId=example -DartifactId=my-app

Choose whichever grails version, group ID and artifact ID you want for your application, but everything else must be as written. This will create a new Maven project with a POM and a couple of other files. What you won't see is anything that looks like a Grails application. So, the next step is to create the project structure that you're used to. But first, to set target JDK to Java 6, do that now. Open my-app/pom.xml and change

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.5</source>
    <target>1.5</target>
  </configuration>
</plugin>
to
<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.6</source>
    <target>1.6</target>
  </configuration>
</plugin>

Then you're ready to create the project structure:

cd my-app
mvn initialize

if you see a message similar to this:

Resolving plugin JAR dependencies …
:: problems summary ::
:::: WARNINGS
        module not found: org.hibernate#hibernate-core;3.3.1.GA

you need to add the plugins manually to application.properties:

plugins.hibernate=2.0.0
plugins.tomcat=2.0.0

then run

mvn compile

and the hibernate and tomcat plugins will be installed.

Now you have a Grails application all ready to go. The plugin integrates into the standard build cycle, so you can use the standard Maven phases to build and package your app: mvn clean , mvn compile , mvn test , mvn package , mvn install .

You can also use some of the Grails commands that have been wrapped as Maven goals:

For a complete, up to date list, run mvn grails:help

Mavenizing an existing project

Creating a new project is great way to start, but what if you already have one? You don't want to create a new project and then copy the contents of the old one over. The solution is to create a POM for the existing project using this Maven command (substitute the version number with the grails version of your existing project):

mvn org.grails:grails-maven-plugin:1.3.2:create-pom -DgroupId=com.mycompany
When this command has finished, you can immediately start using the standard phases, such as mvn package. Note that you have to specify a group ID when creating the POM.

You may also want to set target JDK to Java 6; see above.

Adding Grails commands to phases

The standard POM created for you by Grails already attaches the appropriate core Grails commands to their corresponding build phases, so "compile" goes in the "compile" phase and "war" goes in the "package" phase. That doesn't help though when you want to attach a plugin's command to a particular phase. The classic example is functional tests. How do you make sure that your functional tests (using which ever plugin you have decided on) are run during the "integration-test" phase?

Fear not: all things are possible. In this case, you can associate the command to a phase using an extra "execution" block:

<plugin>
    <groupId>org.grails</groupId>
    <artifactId>grails-maven-plugin</artifactId>
    <version>1.3.2</version>
    <extensions>true</extensions>
    <executions>
        <execution>
            <goals></goals>
        </execution>
        <!-- Add the "functional-tests" command to the "integration-test" phase -->
        <execution>
            <id>functional-tests</id>
            <phase>integration-test</phase>
            <goals>
                <goal>exec</goal>
            </goals>
            <configuration>
                <command>functional-tests</command>
            </configuration>
        </execution>
    </executions>
</plugin>

This also demonstrates the grails:exec goal, which can be used to run any Grails command. Simply pass the name of the command as the command system property, and optionally specify the arguments with the args property:

mvn grails:exec -Dcommand=create-webtest -Dargs=Book

Debugging a Grails Maven Project

Maven can be launched in debug mode using the "mvnDebug" command. To launch your Grails application in debug, simply run:

mvnDebug grails:run-app

The process will be suspended on startup and listening for a debugger on port 8000.

If you need more control of the debugger, this can be specified using the MAVEN_OPTS environment variable, and launch Maven with the default "mvn" command:

MAVEN_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"
mvn grails:run-app

Raising issues

If you come across any problems with the Maven integration, please raise a JIRA issue as a sub-task of GRAILS-3547.