4. The Command Line

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

However, Griffon takes it a bit further through the use of convention and the griffon command. When you type:

griffon [command name]
Griffon does a search in the following directories for Gant scripts to execute:

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

griffon run-app

Results in a search for the following files:

If multiple matches are found Griffon will give you a choice of which one to execute. When Griffon executes a Gant script, it invokes the "default" target defined in that script. If there is no default, Griffon will quit with an error.

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

griffon help

Which outputs usage instructions and the list of commands Griffon is aware of:

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

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

Available Targets (type griffon help 'target-name' for more info): griffon clean griffon compile griffon package ...

The command interpreter is able to expand abbreviations following a camel case convention.

Examples:

griffon tA // expands to test-app
griffon cAd // expands to create-addon
griffon cIT // expands to create-integration-test

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

4.1 Creating Gant Scripts

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

griffon 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 Griffon") {
	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/main", destdir:"output")
}

As demonstrated in the script above, there is an implicit ant variable that allows access to the Apache Ant API.

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's source files.") {
	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 allows you to 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.2 Re-using Griffon scripts

Griffon 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 and package scripts.

Pulling in targets from other scripts

Gant allows you to 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 specialized. If you're interested, look into the Gant documentation.

Core Griffon 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 Griffon targets. Instead, you should use the special griffonScript() method that is provided by the Griffon command launcher (note that this is not available in normal Gant scripts, just Griffon ones).

The syntax for the griffonScript() method is pretty straightforward: simply pass it the name of the Griffon script you want to include, without any path information. Here is a list of Griffon scripts that you may want to re-use:
ScriptDescription
_GriffonSettingsYou really should include this! Fortunately, it is included automatically by all other Griffon scripts bar one (_GriffonProxy), so you usually don't have to include it explicitly.
_GriffonEventsIf you want to fire events, you need to include this. Adds an event(String eventName, List args) method. Again, included by almost all other Griffon scripts.
_GriffonClasspathSets up compilation, test, and runtime classpaths. If you want to use or play with them, include this script. Again, included by almost all other Griffon scripts.
_GriffonProxyIf you want to access the internet, include this script so that you don't run into problems with proxies.
_GriffonArgParsingProvides 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.
_GriffonTestContains all the shared test code. Useful if you want to add any extra tests.
RunAppProvides all you need to run the application in standalone mode.
RunAppletProvides all you need to run the application in applet mode.
RunWebstartProvides all you need to run the application in webstart mode.

There are many more scripts provided by Griffon, 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 re-use.

Script architecture

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

Internal scripts are all about code sharing and re-use. 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. Say 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 << griffonScript("_GriffonTest")

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

Here are a few general guidelines on writing scripts:

4.3 Hooking into Events

Griffon provides the ability to hook into scripting events. These are events triggered during execution of Griffon 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. Griffon searches for these scripts in the following locations:

Whenever an event is fired, all the registered handlers for that event are executed. Note that the registration of handlers is performed automatically by Griffon, 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. Griffon provides some standard events, which are documented in the command line reference guide. For example the compile command fires the following events:

Triggering events

To trigger an event simply call the event() closure:

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 artifact
CreatedFilefileNameCalled whenever a project source filed is created, not including files constantly managed by Griffon
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

4.4 Customising the build

Griffon 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 Griffon build.

The defaults

In order to customize a build, you first need to know what you can customize. The core of the Griffon build configuration is the griffon.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
griffonWorkDirgriffon.work.dir$USER_HOME/.griffon/<griffonVersion>
projectWorkDirgriffon.project.work.dir<griffonWorkDir>/projects/<baseDirName>
classesDirgriffon.project.class.dir<projectWorkDir>/classes
testClassesDirgriffon.project.test.class.dir<projectWorkDir>/test-classes
testReportsDirgriffon.project.test.reports.dir<projectWorkDir>/test/reports
resourcesDirgriffon.project.resource.dir<projectWorkDir>/resources
projectPluginsDirgriffon.plugins.dir<projectWorkDir>/plugins

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.
griffonHomeThe location of the Griffon installation in use (may be null).
griffonVersionThe version of Griffon being used by the project.
griffonEnvThe current Griffon 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 via the griffonSettings script variable. You can also access it from your code by using the griffon.util.BuildSettingsHolder class, but this isn't recommended.

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:

griffon -Dgriffon.project.work.dir=work compile
or add this option to your griffon-app/conf/BuildConfig.groovy file:
griffon.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.

Available build settings

NameDescription
griffon.compiler.dependenciesLegacy approach to adding extra dependencies to the compiler classpath. Set it to a closure containing "fileset()" entries.
griffon.testing.patternsA list of Ant path patterns that allow you to control which files are included in the tests. The patterns should not include the test case suffix, which is set by the next property.
griffon.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".

4.5 Command Tools Integration

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 Griffon command line to build your application. Fortunately, you can easily integrate the Griffon build system into the main build tools in use today (well, the ones in use in Java projects at least).

Ant Integration

When you invoke the integrate-with command with the -ant option enabled

griffon integrate-with --ant

Griffon creates an Apache Ant build.xml file for you containing the following targets:

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

ant clean

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

It uses the Griffon Ant task to hook into the existing Griffon build system. The task allows you to run any Griffon 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="griffonTask"
         classname="griffon.ant.GriffonTask"
         classpathref="griffon.classpath"/>

This raises the question: what should be in "griffon.classpath"? The task itself is in the "griffon-cli" 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 Griffon installation directory to use for the build.Yes, unless classpath is specified.
classpathrefClasspath to load Griffon from. Must include the "griffon-bootstrap" artifact and should include "griffon-scripts".Yes, unless home is set or you use a classpath element.
scriptThe name of the Griffon script to run, e.g. "TestApp".Yes.
argsThe arguments to pass to the script, e.g. "-unit -xml".No. Defaults to "".
environmentThe Griffon 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:

How you populate these paths is up to you. If you are using 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

TBD

Gradle Integration

When you invoke the integrate-with command with the -gradle option enabled

griffon integrate-with --gradle

Griffon creates a Gradle build.gradle file for you. From here you can call the standard Gradle commands such as clean, assemble and build to build your application. You can also use griffon as a command prefix to execute any of the regular Griffon command targets such as

gradle griffon-run-app

4.6 The Griffon Wrapper

This neat feature lets you execute Griffon commands without having a previously installing Griffon in your environment. This is a perfect fit for running tests in a continuous integration environment like Jenkins as there are no other requirements than a matching JDK.

When an application or plugin are created you'll get also the hooks for calling the wrapper, even configuring it in case you need it to point to a different Griffon release. These files are

The first 2 files define platform dependent launch scripts. The third file contains the required classes to bootstrap the wrapper itself. The last file defines the configuration that the wrapper requires to work properly.

The wrapper works in the same way as the Griffon command, this means you can feed it every single command target and parameter the Griffon command accepts, like the following ones

./griffonw run-app

Compiles and runs the application in standalone mode.

./griffonw list-plugin-updates -install

Displays a list of available updates for all plugins installed and proceeds to update them if the confirmation is successful.

4.7 Command Line Options

The following command line options only have meaning while building the project. They have no effect when running the application once it has been packaged.

It's worth noting that all of the following options can also be specified in either griffon-app/conf/BuildConfig.groovy (local to project) or $USER_HOME/.griffon/settings.groovy (global to all projects), with the caveat that values specified at the command prompt will have precedence over those specified in the config file.

4.7.1 Verbose Output

Scripts have the choice of printing to the console whenever they need to communicate something to the developer. They would normally use a standard println sentence. Sometimes it's useful to know what a script is doing with further detail but it makes no sense to see that information every single time. A conditional output is required.

All scripts inherit a debug() closure that will print its argument to stdout if an only if the following flag is enabled: griffon.cli.verbose. As an example, the following script has two print outs

includeTargets << griffonScript("Init")
target(main: "The description of the script goes here!") {
    println 'Hello world!'
    debug 'Hello World (debug)'
}
setDefaultTarget(main)

Running the script without the flag will print out 'Hello World!' all the time but never the second one

$ griffon hello
Welcome to Griffon 0.9.5-rc2 - http://griffon.codehaus.org/
Licensed under Apache Standard License 2.0
Griffon home is set to: /usr/local/griffon
…
Environment set to development
Hello world!

The second message will only appear if you specify the verbose flag

$ griffon -Dgriffon.cli.verbose=true hello
Welcome to Griffon 0.9.5-rc2 - http://griffon.codehaus.org/
Licensed under Apache Standard License 2.0
Griffon home is set to: /usr/local/griffon
…
Environment set to development
Hello world!
[11/11/10 4:43:04 PM] Hello World (debug)

4.7.2 Disable AST Injection

Since Griffon 0.9.1 all artifacts now share a common interface (GriffonArtifact). They may implement additional interfaces that define their role in a better way. For example controllers implement GriffonController whereas models implement GriffonModel. Despite this, you are not forced to implement these interfaces yourself, the Griffon compiler can do the work for you. It will even inject the appropriate behavior to classes that extend from base types other than Object. All this is done by leveraging the powerful AST Transformations framework introduced in Groovy 1.6.

If this feature ever gets in the way then you can disable it with the following command flag

griffon -Dgriffon.disable.ast.injection=true compile

Be sure to clean the project before using this flag, otherwise some classes may still have the AST additions weaved into their bytecode.

4.7.3 Disable Default Imports

Another feature introduced in Griffon 0.9.1 is the ability to define default imports for artifacts and scripts.

If this feature proves to be a disadvantage then disable it with the following command flag

griffon -Dgriffon.disable.default.imports=true compile

4.7.4 Disable Conditional Logging Injection

Griffon 0.9.1 added a log property to all artifacts, and enabled logging on addons. Groovy 1.8 adds a new set of AST transformations, @Log being one of them. It's job is to transform an unguarded logging statement into a guarded one. Starting with 0.9.2, Griffon can do the same without the need of annotating artifacts or addons with @Log.

If this feature proves to be a disadvantage then disable it with the following command flag

griffon -Dgriffon.disable.logging.injection=true compile

4.7.5 Disable Threading Injection

Griffon 0.9.2 adds the option for all controller actions to be executed off the UI thread automatically. This feature breaks backward compatibility with previous releases.

In order to regain the previous behavior you can disable this feature by specifying the following command flag

griffon -Dgriffon.disable.threading.injection=true compile

4.7.6 Default Answer in Non Interactive Mode

Sometimes a command may require the user to specify a missing value. When the build is run in interactive mode (the default mode) then it's just a matter of typing the value in the console. However, if the build is run in non-interactive mode then it's very likely it will fail.

For this reason, the Griffon build accepts the definition of a default answer if the griffon.noninteractive.default.answer key is specified, like this

griffon -Dgriffon.noninteractive.default.answer=y release-plugin

Be warned that this setting applies to every single input asked by a command.

4.7.7 Plugin Install Failure Strategies

Failures may occur during plugin installation. It may be the case that a plugin could not be found in the configured repositories, or a JAR dependency failed to be resolved. When this happens the build will try its best cope with the error, usually by continuing installing remainder plugin dependencies (if any).

This behavior can be altered by specifying a value for griffon.install.failure. Accepted values are:

ValueDescription
abortAborts the installation sequence, even if there are other plugins left to be installed. It will also delete all installed plugins in the current session.
continueContinues with the next plugin in the list. this is the default behavior.
retryRetries failed plugins a second time. A second failure skips the plugin from being installed but does not affect any other plugins that have been successfully installed or are yet to be installed.

For example, to return the build to its previous behavior (abort on failures) you'll type the following in your command prompt

griffon -Dgriffon.install.failure='abort' compile

4.7.8 Default Artifact Repository for Searching

The Griffon build assumes griffon-legacy to be the default Artifact Repository to be searched when querying for artifacts (either to list them, get some info or install them). This setting can be altered by specifying a value for griffon.artifact.repository.default.search. The value must be a valid repository name available in the configuration files.

For example, a local repository identified by the name 'my-local-repo' can be set as the default search repository like so

griffon -Dgriffon.artifact.repository.default.search='my-local-repo' install-plugin cool-plugin

4.7.9 Default Artifact Repository for Caching

When a plugin or archetype is downloaded from an artifact repository the Griffon build will place a copy of it in the griffon-local repository. This speeds up searches and further plugin installations. If you would like to specify a different local repository to be used as a cache then define a value for the griffon.artifact.repository.default.install key.

Assuming that 'my-local-repo' is configured in the project's settings then the following command will download the miglayout plugin and place a copy in that specific repository.

griffon -Dgriffon.artifact.repository.default.install='my-local-repo' install-plugin miglayout

4.7.10 Disable Automatic Local Repository Synchronization

Section 4.7.9 describes that copies of plugins and archetypes will be placed in a local repository whenever they are downloaded from other repositories. You can disable this feature altogether by specifying a value for griffon.disable.local.repository.sync as true, like the following example shows

griffon -Dgriffon.disable.local.repository.sync=true install-archetype scala

4.8 The Griffon Shell

Starting with Griffon 0.9.5 there's a new command line tool at your disposal: the Griffon Shell or griffonsh for short. This is an interactive shell that can be kept running in the background, this way you don't pay the penalty of starting a new JVM every time you invoke a command. Other benefits are the bypass of dependency resolution if dependencies have not changed from the last command invocation. Here's a sample usage session:

$ griffonsh
Welcome to Griffon 0.9.5-rc2 - http://griffon.codehaus.org/
Licensed under Apache Standard License 2.0
Griffon home is set to: /usr/local/griffon

Type 'exit' or ^D to terminate this interactive shell

griffon> compile Resolving dependencies… Dependencies resolved in 903ms. Environment set to development Resolving plugin dependencies … Plugin dependencies resolved in 1502 ms. [mkdir] Created dir: /Users/joe/.griffon/0.9.5-rc2/projects/sample/classes/cli [mkdir] Created dir: /Users/joe/.griffon/0.9.5-rc2/projects/sample/classes/main [mkdir] Created dir: /Users/joe/.griffon/0.9.5-rc2/projects/sample/classes/test [mkdir] Created dir: /Users/joe/.griffon/0.9.5-rc2/projects/sample/test-classes [mkdir] Created dir: /Users/joe/.griffon/0.9.5-rc2/projects/sample/test-resources [mkdir] Created dir: /Users/joe/.griffon/0.9.5-rc2/projects/sample/resources [griffonc] Compiling 8 source files to /Users/joe/.griffon/0.9.5-rc2/projects/sample/classes/main [griffonc] Compiling 4 source files to /Users/joe/.griffon/0.9.5-rc2/projects/sample/classes/main griffon> run-app Resolving dependencies… Dependencies resolved in 1ms. [mkdir] Created dir: /Users/joe/.griffon/0.9.5-rc2/projects/sample/resources/griffon-app/i18n [mkdir] Created dir: /Users/joe/.griffon/0.9.5-rc2/projects/sample/resources/griffon-app/resources [copy] Copying 1 file to /Users/joe/.griffon/0.9.5-rc2/projects/sample/resources/griffon-app/i18n [copy] Copying 8 files to /Users/joe/.griffon/0.9.5-rc2/projects/sample/resources/griffon-app/resources [copy] Copying 1 file to /Users/joe/.griffon/0.9.5-rc2/projects/sample/classes/main [copy] Copying 11 files to /Users/joe/.griffon/0.9.5-rc2/projects/sample/resources [copy] Copied 8 empty directories to 8 empty directories under /Users/joe/.griffon/0.9.5-rc2/projects/sample/resources [copy] Copying 1 file to /projects/sample/staging [copy] Copying 1 file to /projects/sample/staging [copy] Copying 1 file to /projects/sample/staging [copy] Copying 1 file to /projects/sample/staging [copy] Copying 1 file to /projects/sample/staging [copy] Copying 1 file to /projects/sample/staging [copy] Copying 1 file to /projects/sample/staging [copy] Copying 1 file to /projects/sample/staging Launching application … 2012-02-07 17:27:11,007 [main] INFO griffon.swing.SwingApplication - Initializing all startup groups: [sample] 2012-02-07 17:27:16,555 [AWT-EventQueue-0] INFO griffon.swing.SwingApplication - Shutdown is in process [delete] Deleting directory /projects/sample/staging/macosx64 [delete] Deleting directory /projects/sample/staging/macosx griffon> clean Resolving dependencies… Dependencies resolved in 1ms. [delete] Deleting directory /Users/joe/.griffon/0.9.5-rc2/projects/sample/classes/cli [delete] Deleting directory /Users/joe/.griffon/0.9.5-rc2/projects/sample/classes/main [delete] Deleting directory /Users/joe/.griffon/0.9.5-rc2/projects/sample/classes/test [delete] Deleting directory /Users/joe/.griffon/0.9.5-rc2/projects/sample/test-classes [delete] Deleting directory /Users/joe/.griffon/0.9.5-rc2/projects/sample/test-resources [delete] Deleting directory /Users/joe/.griffon/0.9.5-rc2/projects/sample/resources [delete] Deleting directory /projects/sample/staging griffon>

This command environment accepts all commands available to the griffon command (except those that let you create a new project) plus a few more that are unique to the griffon shell. Please refer to the help command for more information on those extra commands.