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

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(' ')
}
...
}

Related

Execute Groovy script from Gradle without compiling Java

I have a Java project with Gradle.
Also I use Groovy to generate some class that will be used in Java code. Gradle executes script in separate task below:
task generateClass(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = 'generatorScript'
}
If I run this task, it first starts Java compilation, and only after that executes script. So if compilation failed, my generator script will not be executed. As it was mentioned, script generates one class, which my Java code is actually depends on, so, if not generated, Java will not be compiled. Vicious circle.
Script itself does not depend on some Java classes and is placed in separate sources directory:
/src
/main
/java
/...(java classes)
/groovy
generatorScript.groovy
It seems like nothing interferes me to execute script separately and independently from Java compilation.
How can I achieve that?
The problem is that you have the generator groovy script in the main sourcesets, and you try to compile this groovy script to use it as classpath for your JavaExec task. This is why compileJava task is executed, I guess.
You could do in another way, using groovy.ui.GroovyMain to execute your script, with following solution based on this link
configurations {
// a dedicated Configuration for Groovy classpath
groovyScript
}
dependencies {
// Set Groovy dependency so groovy.ui.GroovyMain can be found.
groovyScript localGroovy()
}
task generateClass(type: JavaExec) {
// Set class path used for running Groovy command line.
classpath = configurations.groovyScript
// Main class that runs the Groovy command line.
main = 'groovy.ui.GroovyMain'
// Pass your groovy script as argument of the GroovyMain main
// (can be improved)
args 'src/main/groovy/generatorScript.groovy'
}

How to pass command-line arguments to main class in gradle?

I am creating simple Java class and I would like to create out-of-the-box launcher by using gradle.
So I want to be able to run Java program via gradle:
gradlew clean run These are my command line arguments where These are my command line arguments are passed directly to my public static void main(String... args) method.
I am using the apply plugin: "application" which gives me the run task. But when I am running this 'as is' I've got:
* What went wrong:
Task 'These' not found in root project 'question1'. Some candidates are: 'test'.
Gradle interprets each argument not starting with a hyphen (-) as task name to define which tasks will be executed during the build. Since a task with the name These does not exist, the build fails.
You are using the Gradle Application Plugin, which, as you already stated, provides a run task. The docs show, that the run task is of the type JavaExec. So, to apply your arguments, add them to the run task via args:
run {
args 'These are my command line arguments'
}
To modify the arguments for each build without changing the build.gradle file, simply use project properties:
run {
args findProperty('runArgs')
}
And call gradle clean run -PrunArgs='These are my command line arguments'

Running Single cucumber-jvm .feature file from Gradle

I am integrating a cucumber-java with an existing gradle java project, that has a focus on test automation. There is no production code within this project, so making the entire project makes little sense.
What I would like to do is to create gradle tasks or a single gradle task with a -D property that specifies a cucumber .feature file to run cucumber-jvm on. All of the examples that I've seen show how to get cucumber-jvm to run as part of the build process. Instead, I would like to define a task testCucumber(type: Test) to run a single .feature file. How would I go about doing this?
I was able to get this to work by using a javaexec task in gradle.
javaexec {
main = "cucumber.api.cli.Main"
classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
args = ['--plugin', 'junit:target/cucumber-junit-report.xml', '--plugin', 'pretty', '--glue', 'StepDefinitions', 'src/test/Features/FeatureFilename.feature']
}
This is assuming that all step definitions are defined within a package called "StepDefinitions".

Maven create specific ksh with the list of dependencies

This is a maven question, not a ksh one.
I am trying to generate dynamically with maven a ksh script to launch a java application in production environment.
The aim of the script is to setup the classpath of the java application and launch it.
The ksh at end should be like that:
#!/bin/ksh
launchbatch() {
$JRE_HOME/bin/java -cp $BATCH_CLASSPATH $PRG_NAME
}
setclasspath() {
BATCH_CLASSPATH=$BATCH_PROPERTIES/
BATCH_CLASSPATH="$BATCH_CLASSPATH:$BATCH_LIB/activation-1.1.jar"
BATCH_CLASSPATH="$BATCH_CLASSPATH:$BATCH_LIB/annotations-1.0.0.jar"
BATCH_CLASSPATH="$BATCH_CLASSPATH:$BATCH_LIB/antlr-2.7.6.jar"
BATCH_CLASSPATH="$BATCH_CLASSPATH:$BATCH_LIB/aopalliance-1.0.jar"
...
}
setclasspath
launchbatch
How could I generate the content of the setclasspath function directly with maven so that it will inject all maven dependencies?
Note: I do not want to specify a directory containing all the jars in the classpath as the $BATCH_LIB directory is common to several batch applications.
So, this simple solution is not possible for me:
setclasspath() {
BATCH_CLASSPATH=$BATCH_PROPERTIES/
BATCH_CLASSPATH="$BATCH_CLASSPATH:$BATCH_LIB/"
}
I would suggest to take a deep look at the appassembler-maven-plugin which generates such scripts.
It creates bash script but i would assume that it runes in many environments. You can find an example of how it works here.

How do I generate the class path for a Gradle project?

I have a gradle project with multiple packages. After the build, each package generates its jar files in build/libs. The external jar dependencies are pulled into ~/.gradle. I would now like to run the service locally from the commandline with the appropriate classpath. For this purpose, I am writing a script that constructs the classpath. The problem is that the script does not understand all the external dependencies and hence cannot construct the classpath. Is there a way for gradle to help with this? Ideally, I would like to dump all the dependencies into a folder at the end of the build.
Firstly, i would suggest using the application plugin if you can, since it takes care of this already.
If you want to dump the classpath to a file yourself, the simplest way is something like:
task writeClasspath << {
buildDir.mkdirs()
new File(buildDir, "classpath.txt").text = configurations.runtime.asPath + "\n"
}
If you want to actually copy all the libraries on the classpath into a directory, you can do:
task copyDependencies(type: Copy) {
from configurations.runtime
into new File(buildDir, "dependencies")
}
You could try something like this in your build script:
// add an action to the build task that creates a startup shell script
build << {
File script = file('start.sh')
script.withPrintWriter {
it.println '#!/bin/sh'
it.println "java -cp ${getRuntimeClasspath()} com.example.Main \"\$#\""
}
// make it executable
ant.chmod(file: script.absolutePath, perm: 'u+x')
}
String getRuntimeClasspath() {
sourceSets.main.runtimeClasspath.collect { it.absolutePath }.join(':')
}

Categories