The Scala equivalent of JavaExec?


(Mark Petrovic) #1

HI. I note that the Gradle docs include an example of how to run a Java app with the JavaExec task. But how would I run a Scala app from Gradle?

Thanks.


(Peter Niederwieser) #2

‘JavaExec’ really is ‘JvmExec’. You can use it just as well to execute Scala (or Groovy etc.) code. Just make sure to include the Scala libraries on the task’s class path (if they aren’t already).


(Mark Petrovic) #3

Thank you. This is what I’ve come up with, though I suspect it’s a bit naive:

task slurp(type: JavaExec, dependsOn: classes) {
    main = 'slurper.App'
    args = "$srcDbPassword $xferId".split().toList()
    classpath sourceSets.main.runtimeClasspath
    classpath configurations.runtime
}

However, one problem remains. When I want to just build the project, as in

$ gradle clean build

I now get

Could not find property ‘srcDbPassword’ on task ‘:slurp’.

Is there a Gradle idiom that allows me to avoid setting the two properties when I want to execute tasks other than “slurp”?

Thank you.


(Mark Petrovic) #4

Incidentally, I should have mentioned that the JavaExec task works for this Scala project. iow, when I do

$ gradle clean build slurp -PsrcDbPassword=foo -PxferId=bar

my slurper.App runs as intended. Good.

So what remains is to figure out how to essentially make the -P properties optional for the cases where I want to run some task other than “slurp”. Sorry if that was not initially clear.

And here is the entirety of my build script thus far:

apply plugin: 'scala'
  repositories {
    mavenCentral()
}
  task slurp(type: JavaExec, dependsOn: classes) {
    main = 'slurper.App'
    args = "$srcDbPassword $xferId".split().toList()
    classpath sourceSets.main.runtimeClasspath
    classpath configurations.runtime
}
  dependencies {
    // Libraries needed to run the scala tools
    scalaTools 'org.scala-lang:scala-compiler:2.8.1'
    scalaTools 'org.scala-lang:scala-library:2.8.1'
      // Libraries needed for scala api
    compile 'org.scala-lang:scala-library:2.8.1'
      // MySQL
    compile 'mysql:mysql-connector-java:5.1.21'
}

(Mark Petrovic) #5

I found a better solution, using system properties:

apply plugin: 'scala'
  repositories {
    mavenCentral()
}
  task slurp(type: JavaExec, dependsOn: classes) {
    main = 'slurper.App'
    if (System.properties['srcDbPassword'] == null || System.properties['xferId'] == null) {
        println("Usage:
gradle slurp -D<dbPassword> -D<xferId>")
        System.exit(-1)
    }
    args = [System.properties['srcDbPassword'], System.properties['xferId']]
    classpath sourceSets.main.runtimeClasspath
    classpath configurations.runtime
}
  dependencies {
    // Libraries needed to run the scala tools
    scalaTools 'org.scala-lang:scala-compiler:2.8.1'
    scalaTools 'org.scala-lang:scala-library:2.8.1'
      // Libraries needed for scala api
    compile 'org.scala-lang:scala-library:2.8.1'
      // MySQL
    compile 'mysql:mysql-connector-java:5.1.21'
}

I’m still open to suggestions on more elegant solutions.

Thank you.


(Mark Petrovic) #6

I found one solution that works for both “clean build” and “slurp”. It still feels rather awkward. Suggestions welcome.

apply plugin: 'scala'
  repositories {
    mavenCentral()
}
  task slurp(type: JavaExec, dependsOn: classes) {
    main = 'slurper.App'
    args = [System.properties['srcDbPassword'], System.properties['xferId']]
    classpath sourceSets.main.runtimeClasspath
    classpath configurations.runtime
}
slurp.doFirst {
    if (System.properties['srcDbPassword'] == null || System.properties['xferId'] == null) {
        println("Usage:
gradle slurp -D<dbPassword> -D<xferId>")
        System.exit(-1)
    }
}
  dependencies {
    // Libraries needed to run the scala tools
    scalaTools 'org.scala-lang:scala-compiler:2.8.1'
    scalaTools 'org.scala-lang:scala-library:2.8.1'
      // Libraries needed for scala api
    compile 'org.scala-lang:scala-library:2.8.1'
      // MySQL
    compile 'mysql:mysql-connector-java:5.1.21'
}

Thank you.


(Peter Niederwieser) #7

It won’t get fundamentally simpler than that. But you shouldn’t need ‘classpath configurations.runtime’, and you should do ‘throw new GradleException(“some message”)’ instead of the ‘println’ and ‘System.exit(-1)’. You could do ‘if (slurp.args.contains(null))’ in ‘doFirst’. And the current usage message isn’t quite correct.


(Mark Petrovic) #8

Thank you.

What does “classpath configurations.runtime” actually do, even though I do not need it?


(Peter Niederwieser) #9

Typically it will be redundant to add both ‘sourceSets.main.runtimeClasspath’ and ‘configurations.runtime’, because the former will be a superset of the latter.


(Mark Petrovic) #10

One last refinement in case anyone is still reading:

task slurp(type: JavaExec, dependsOn: classes) {
    doFirst {
        if (System.properties[project.ext.dbpwd] == null || System.properties[project.ext.xferId] == null) {
            throw new GradleException(sprintf("Usage:
gradle slurp -D%s=<dbPassword> -D%s=<xferId>\n", project.ext.dbpwd, project.ext.xferId))
        }
    }
      main = 'slurper.App'
    args = [System.properties[project.ext.dbpwd], System.properties[project.ext.xferId]]
    classpath sourceSets.main.runtimeClasspath
}

(Peter Niederwieser) #11

You can leave off ‘.ext’ when reading a property. And the usage message is still wrong. :slight_smile: (-D instead of -P, wrong values for %s.)


(Mark Petrovic) #12

If I remove “.ext” from the properties, I get this (Gradle 1.0);

Dynamic properties are deprecated: http://gradle.org/docs/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html Deprecated dynamic property: “dbpwd” on “root project ‘slurper’”, value: “srcDbPassword”. Deprecated dynamic property: “xferId” on “root project ‘slurper’”, value: “xferId”.

I must be looking right past the -D/-P issue. I see -D and I think the values are correct, but I’ll look closer later.


(Mark Petrovic) #13

Woops. I missed the “when reading a property” in your reply. Got it.