Proper usage of project Exec method


I am trying to execute a command on a list of files in order to generate mail templates. The command is using a npm library executable.

Here is the tasks that installs npm:

task npmInstall(type: Exec) {
  description "npm install"
  commandLine 'npm', 'install'

Here is the tasks that generates the templates

task processMailTemplates {
  description "Processes mail templates"
  dependsOn npmInstall

  outputs.upToDateWhen { false }

 doLast {
    def templateSrcDir = "src/main/templates/mail/"
    def templateDestDir = "$buildDir/generated-mail-templates/META-INF/templates/mail/"

    mkdir templateDestDir

    def templateNames = []

     fileTree(dir: templateSrcDir, include: '**/*.html').visit {
         FileVisitDetails details -> templateNames <<

    templateNames.each { templateName -> inlineCss(templateSrcDir + templateName, templateDestDir + templateName) }

And here is the method that is using the project Exec method

static def inlineCss(src, dest) {
  def juice = 'node_modules/.bin/juice'
  def juiceResourcesDir = 'src/main/templates/misc'
  def juiceArgs = "--options-file ${juiceResourcesDir}/juiceOptions.json --css 
  exec {
      commandLine "${juice} ${juiceArgs} ${src} ${dest}"

Somehow, something is wrong with the way I call the exec method. I get the following error:

> Task :bignibou-common:processMailTemplates FAILED

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/julien/Documents/projects/bignibou/bignibou-common/build.gradle' line: 105

* What went wrong:
Execution failed for task ':bignibou-common:processMailTemplates'.
> No signature of method: static build_b03zu5g6d6c6aaxn650fxoe1c.exec() is applicable for argument types: (build_b03zu5g6d6c6aaxn650fxoe1c$_inlineCss_closure8) values: [build_b03zu5g6d6c6aaxn650fxoe1c$_inlineCss_closure8@3df32f9b]
  Possible solutions: exec(groovy.lang.Closure), exec(org.gradle.api.Action), grep(), every(), sync(org.gradle.api.Action), grep(java.lang.Object)

Indicating a wrong usage of closures…

Can someone please advise ?

I think you’re trying to call, but your method is static def, so there’s no instance of project is available on that level of your build script.

Potential solutions:

  • inline your method so that the processMailTemplates configuration closure provides you with Task#project
  • make def non-static, so you get Project#project from the buildscript’s context
  • modify the signature to static def inlineCss(Project project, src, dest) and use project.exec ...;
    simply pass in project inside your each that will access Task#project from the configuration closure.

Note: to access Project#project or Task#project in the script you just say project there’s no need for qualification the Groovy compiler will figure out which closure can resolve it, but it’s helpful to know what you’re actually accessing, for example so you can look up the docs.

1 Like