5.2 Creating Custom Scripts

You can create your own Command scripts by running the create-script command from the root of your project. For example the following command will create a script called src/main/scripts/hello-world.groovy:

  1. grails create-script hello-world
In general Grails scripts should be used for scripting the Gradle based build system and code generation. Scripts cannot load application classes and in fact should not since Gradle is required to construct the application classpath.

See below for an example script that prints "Hello World":

  1. description "Example description", "grails hello-world"
  2. println "Hello World"

The description method is used to define the output seen by grails help and to aid users of the script. The following is a more complete example of providing a description taken from the generate-all command:

  1. description( "Generates a controller that performs CRUD operations and the associated views" ) {
  2. usage "grails generate-all <<DOMAIN CLASS>>"
  3. flag name:'force', description:"Whether to overwrite existing files"
  4. argument name:'Domain Class', description:'The name of the domain class'
  5. }

As you can see this description profiles usage instructions, a flag and an argument. This allows the command to be used as follows:

  1. grails generate-all MyClass --force

Template Generation

Plugins and applications that need to define template generation tasks can do so using scripts. A example of this is the Scaffolding plugin which defines the generate-all and generate-controllers commands.

Every Grails script implements the TemplateRenderer interface which makes it trivial to render templates to the users project workspace.

The following is an example of the create-script command written in Groovy:

  1. description( "Creates a Grails script" ) {
  2. usage "grails create-script <<SCRIPT NAME>>"
  3. argument name:'Script Name', description:"The name of the script to create"
  4. flag name:'force', description:"Whether to overwrite existing files"
  5. }
  6. def scriptName = args[0]
  7. def model = model(scriptName)
  8. def overwrite = flag('force') ? true : false
  9. render template: template('artifacts/Script.groovy'),
  10. destination: file("src/main/scripts/${model.lowerCaseName}.groovy"),
  11. model: model,
  12. overwrite: overwrite

If a script is defined in a plugin or profile, the template(String) method will search for the template in the application before using the template provided by your plugin or profile. This allows users of your plugin or profile to customize what gets generated.

It is common to provide an easy way to allow users to copy the templates from your plugin or profile. Here is one example on how the angular scaffolding copies templates.

  1. templates("angular/**/*").each { Resource r ->
  2. String path = r.URL.toString().replaceAll(/^.*?META-INF/, "src/main")
  3. if (path.endsWith('/')) {
  4. mkdir(path)
  5. } else {
  6. File to = new File(path)
  7. SpringIOUtils.copy(r, to)
  8. println("Copied ${r.filename} to location ${to.canonicalPath}")
  9. }
  10. }

The "model"

Executing the model method with a Class/String/File/Resource will return an instance of Model. The model contains several properties that can help you generate code.

Example:

  1. def domain = model(com.foo.Bar)
  2. domain.className == "FooBar"
  3. domain.fullName == "com.foo.FooBar"
  4. domain.packageName == "com.foo"
  5. domain.packagePath == "com/foo"
  6. domain.propertyName == "fooBar"
  7. domain.lowerCaseName == "foo-bar"

In addition, an asMap method is available to turn all of the properties into a map to pass to the render method.

Working with files

All scripts have access to methods on the FileSystemInteraction class. It contains helpful methods to copy, delete, and create files.