Documentation for the gradle run task? - java

After a long time of searching I was still not able to find any official documents for the gradle run task. I assume that is because it is actually JavaExec task type.
It also seems that the run task is only available with the application plugin. Its docs mention some of the available arguments such as --debug-jvm and --args (for passing command-line arguments to the application's main method).
What I actually wanted to find out how I can pass arguments to the JVM on the command-line, i.e. an equivalent of setting application { applicationDefaultJvmArgs = ".." }.
Help appreciated!

You're right, the run task comes from the application plugin and it is a JavaExec task.
A list of all configuration options is available in the documentation of the JavaExec task
You can configure options in your (groovy-)gradle file like so:
tasks.named('run', JavaExec) {
mainClassName = '...MainKt'
applicationDefaultJvmArgs = [ System.getProperty("jvmArgs") ]
classpath = sourceSets.netMain.runtimeClasspath
}

I have now written https://blog.jakubholy.net/2020/customizing-gradle-run-task/ which describes both how to customize the run task and how to customize it on the command line:
apply plugin: 'application'
mainClassName = "my.app.Main"
run {
debugOptions {
enabled = true
server = true
suspend = false
}
systemProperty("my.defaultLogLevel", "debug")
environment("OTEL_EXPORTER", "zipkin")
jvmArgs=["-javaagent:aws-opentelemetry-agent-0.9.0.jar"]
}
As the application plugin documentation states, you can also enable debugging with --debug-jvm or specify arguments with --args="foo --bar". And you can set application { applicationDefaultJvmArgs= []} to apply both to run and the generated start scripts of your distribution.

Related

Fail gradle build if file does not exist [duplicate]

I am starting to use Gradle for an Android application. I would like the build to fail if the developer fails to create a file at a specific location such as ./src/res/values/specialfile.xml
A bit of searching led me to believe that a .doFirst would work
android.doFirst {
assert file("./src/res/values/specialfile.txt").exists()
}
However, Gradle says "unsupported Gradle DSL method found: 'doFirst()'!"
What can I do to assert a file's existence?
doFirst only exists on tasks object. android is not a task.
If would want this test to always be done even if the developer doesn't try to build (for example when running the tasks task), you should simply put in your build.gradle
assert file("./src/res/values/specialfile.txt").exists()
However this is really not recommended as this would be executed even for non build tasks, or even when the model is built for IDE integration.
There is a task called preBuild that is executed before anything in the android build, so you can hook your test to it, either through another task or through doFirst:
preBuild.doFirst {
assert file("./src/res/values/specialfile.txt").exists()
}
One may want to check in a module build.gradle ...
below the plugins configuration block
above the android configuration block
eg. in order to determine which Gradle plugins to apply:
plugins {
id "com.android.application"
}
def json_google = "src/google-services.json";
if (project.file(json_google).exists()) {
println "found: ${project.file(json_google)}"
apply plugin: "com.google.gms.google-services"
apply plugin: "com.google.firebase.crashlytics"
...
} else {
def message = "missing: ${project.file(json_google)}"
// throw new GradleException(message)
println message
}
android { ... }
rootProject.file() and project.file() might be more convenient than file() (it depends). Using assert seems a bit harsh - but then one has to take care that it will not crash elsewhere.
My projects usually have a few optional config files, which the environment may or may not provide, because not every product flavor may require the same set of plugins & config files.

Gradle task not running as demanded (before compiling)

INTRODUCTION
The project is in Kotlin and builds using Gradle. I'm trying to generate a basic data class with some build info, let's say for now that I need it [re]generated every time before running.
Here's the Gradle task I have now:
def generatedDir = "$buildDir/generated"
// noinspection GroovyAssignabilityCheck
task generateBuildInfo {
inputs.property "version", rootProject.version.toString()
inputs.property "name", rootProject.name.toString()
outputs.dir generatedDir
outputs.upToDateWhen { false }
doFirst {
def buildInfoFile = file("$generatedDir/BuildInfo.kt")
buildInfoFile.parentFile.mkdirs()
buildInfoFile.text = """
internal data class BuildInfo(
val version: String = "${project.version.toString() ?: "unspecified"}",
val name: String = "${project.name.toString() ?: "unspecified"}"
)
""".replace(" ", "").trim()
}
}
To be able to resolve this from IntelliJ IDEA, I added my new folder to project sources, and obviously wired up the dependencies, like so:
sourceSets.main.kotlin.srcDirs += generatedDir
project.afterEvaluate {
compileJava.dependsOn generateBuildInfo
compileKotlin.dependsOn generateBuildInfo
}
This is all done in a separate file (to avoid polluting my main scripts). Due to this organization, after applying plugins, I just include the generator in my main script, like this:
apply from: "gradle/scripts/build-info-generator.gradle"
THE PROBLEM
It looks like the generator code is executed only once, after running assemble when I first ran clean on this module. This is not what I want, because when I change some of the project properties (like version), the source does not get updated... as if compileJava/compileKotlin and my custom task are not executed.
They do not appear in build logs as executed.
Is there any way I can run this task every time I want to run my module's launcher? Sure, I can do some smart file comparison to see if generation is needed, but for now I just want it done each time. Am I missing something?
IDEA has its own build system, indepenant from Gradle.
You can configure it to run a Gradle task before its own build task.
You can also configure it to delegate all the build/run tasks to Gradle. But that's not the default.

How to enable assertions in the Gradle run task

By default, Java disables assertions. (The test I'm using here is assert false; as the first line in main().)
I'd like to have them enabled while running my program with gradle run. What's the trick for doing this?
There is a specific flag enableAssertions that you can set to enable assertions. Such flags are often more readable than working with the jvm args directly. It comes down to personal preferences I think.
Instead of working with applicationDefaultJvmArgs you can add the following to your build.gradle file:
run {
enableAssertions = true
}
This configures the run task to enable assertions.
The run task is of type JavaExec, have a look at the documentation if you are interested in other parameters that you can set (e.g., workingDir or heapMaxSize).
tasks.withType(JavaExec) {
enableAssertions = true
}

How to execute command line tools with projects built with gradle?

Running a Java application built with Gradle requires adding to the classpath a directory for each individual library, as it stores them in individual directories.
Therefore, when you look at the command to launch the application in IntelliJ you can easily see a whole screen filled with classpath dependencies.
This is fine for IntelliJ because it can figure them out automatically, but I want to be able to run my command line tool in the terminal, writing arguments there instead of editing my run configuration each time I want to change anything. How can I do so without pasting a whole screen of machine-specific JAR dependencies from the IDE?
Is it possible to do it in a development environment without creating a giant JAR file bundling all the libraries?
Take a look at JavaExec task. You can create a custom task as such:
task customRun(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = "fully.qualified.name.of.your.main"
args = ["100", "1000" ...] // the command line options for your tool
jvmArgs = [ ... ] // additional JVM args you might need
}
Then you can invoke it using gradle customRun. If you want to be able to provide the command line arguments, I would suggest using gradle properties:
gradle -PcustomRunArgs="100 1000" customRun
and modifying the task to grab the arguments:
task ... {
...
if (project.hasProperty('customRunArgs')) {
args = customRunArgs.split(' ')
}
...
}

Perform an action on each file during installApp phase of Gradle build

Here is a minimal build.gradle file I'm using.
apply plugin: 'application'
installApp {
eachFile {
println "$it.name"
loadProperties(it)
}
}
I'm trying to load properties into some placeholders in a properties file located in src/dist/bin. This technique works fine if the properties file is in src/main/resources and I replace installApp with processResources which I am doing in another project within the build.
The println isn't printing anything so it makes sense the placeholders aren't replaced but I don't understand why it's not iterating through all the files the installApp task is copying.
Running this as ./gradlew clean installApp using gradle 1.10.
It appears that the installApp task doesn't run closure passed to the eachFile function. Here is a complete build.gradle file that demonstrates this behavior
apply plugin: "application"
mainClassName = "test.Test"
installApp {
eachFile {
println "$it.name"
}
}
I run gradle clean installApp -i
and around the installApp section get
:installApp (Thread[main,5,main]) started.
:installApp
Executing task ':installApp' (up-to-date check took 0.011 secs) due to:
Output file /Users/joshbrackett/Documents/workspace/gtest/build/install/gtest has changed.
Output file /Users/joshbrackett/Documents/workspace/gtest/build/install/gtest/bin/gtest has been removed.
Output file /Users/joshbrackett/Documents/workspace/gtest/build/install/gtest/lib/gtest.jar has been removed.
:installApp (Thread[main,5,main]) completed. Took 0.748 secs.
I have replicated your issue. I suspect this is a bug. While we investigate further, here is a workaround that worked for me.
make your eachFile call on the applicationDistribution copySpec rather than the installApp task.
applicationDistribution.eachFile {
println "$it.name"
}
I suspect that this is what you want to do anyway, since then it will also be used by the dist tasks.
BTW you may also find that the expand method is of interest http://www.gradle.org/docs/current/javadoc/org/gradle/api/file/CopySpec.html#expand(java.util.Map)
This has changed again in Gradle 2.3 apparently. Now using applicationDistribution doesn't work and you need to use installDist instead.

Categories