Running an application which uses java.io.Console API from Gradle - java

Consider I have a Java (or Kotlin, doesn't really matter) application which uses java.io.Console API, or any other API which manipulates the terminal state (e.g.: net.rubygrapefruit:native-platform):
System.out.println(format("Console is %s.", System.console()));
final Terminals terminals = Native.get(Terminals.class);
final Output out = Stdout;
if (terminals.isTerminal(out)) {
final TerminalOutput stdout = terminals.getTerminal(out);
stdout.bold();
System.out.println("bold text");
stdout.foreground(Color.Magenta);
System.out.println("Magenta");
stdout.reset();
final Prompter prompter = new Prompter(terminals);
prompter.askYesNo("Prompt", true);
prompter.enterText("Text", "default text");
prompter.enterPassword("Password");
prompter.select("Select", asList("foo", "bar", "baz"), 1);
} else {
System.out.println(format("%s is not a terminal.", out));
}
The above code would run just fine when launched by Maven Exec plug-in, but with Gradle (since Gradle tries to make its own output look pretty, with all those bells, whistles and progress bars) the code just prints:
$ gradle --console=plain run
> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :run
Console is null.
Stdout is not a terminal.
BUILD SUCCESSFUL in 0s
2 actionable tasks: 1 executed, 1 up-to-date
Configuring the run task as described here and here:
private val run: JavaExec by tasks
run.apply {
standardInput = System.`in`
standardOutput = System.out
errorOutput = System.err
}
or adding --no-daemon to Gradle's command line args as suggested here doesn't really help (System.in is still an instance of java.io.PipedInputStream, while System.out and System.err are instances of org.gradle.internal.io.LinePerThreadBufferingOutputStream).
Is it possible to make Gradle stop messing with the terminal and allow the application being run to access it?

You're probably assigning them wrongfully, because these both should be ByteArrayOutputStream. And probably they should not even be assigned in Gradle (the assignment of default values is redundant). Use Exec and then execute java -jar fileName, if you shouldn't get it working with JavaExec.

Related

How to run lint for all product flavours in one command - Android?

I have implemented the product flavors for my project. I am building three new application in the same codebase.
After gradle sync, three different flavors have been generated, say flavor1Debug, flavor1Release, flavor2Debug, flavor2Release.
I have moved all flavor specific resources inside the flavor specific res folder. When I tried to run ./gradlew lintRelease(which is supposed to run lint for flavor1Release and flavor2Release), it's not detecting any of the errors
For testing the lint, I have introduced an unused resource inside the res folder of flavor1 and flavor2. I tried to run ./gradlew lintFlavor1Release or ./gradlew lintFlavor2Release, its detecting the error and throwing respectively.
But ./gradlew lintRelease is not throwing any errors. Where am I going wrong?
Try something like this:
make a custom gradle task that will run all those lint tasks separately.
tasks.register("runAllLinters")
afterEvaluate {
if ("lintFlavor1Release" in tasks.names) {
runAllLinters.dependsOn tasks.named("lintFlavor1Release")
}
}
of course, this will trigger only for Flavor1 - so you will need to expand both the if() condition, and the runAllLinters.dependsOn block to depend on ALL flavour-dependant lint tasks.
and finally, you should be able to run it like ./gradlew runAllLinters
Try this:
afterEvaluate {
def LINT_TASK_NAME = "lint"
def lintTask = tasks.findByName(LINT_TASK_NAME)
tasks.findAll { task ->
task.name.startsWith(LINT_TASK_NAME) &&
task.name != LINT_TASK_NAME &&
// remove some standard lint subtasks
!task.name.startsWith("lintFix") &&
!task.name.startsWith("lintAnalyze")
}.each { task -> lintTask.dependsOn.add(task) }
}
This makes task 'lint' to depend on all the other "lintXxxx" tasks except some standard.

How to run command line commands in a compiled Gradle plugin?

How can you execute a CMD command from a Gradle task without the Gradle DSL (commandLine 'echo', ':)'), i.e. something like:
open class MyTask : DefaultTask() {
#TaskAction
fun task() {
Runtime.getRuntime().exec("echo :)") //Doesn't print anything
}
}
Nothing is printed, because the exec method executes given command in a new process, separate to the process handling Gradle task (and has its own I/O streams).
The exec method returns the Process object. Citing docs, the Process "provides control of native processes started by ProcessBuilder.start and Runtime.exec".
So, to capture the output of executed command, it's required to read it from the process of that command.
The simple example of printing output from echo :) could be:
task something {
doLast {
Process echo = Runtime.getRuntime().exec("cmd /c echo :)")
println new BufferedReader(new InputStreamReader(echo.getInputStream())).readLine()
}
}
(I'm having cmd /c command prefix, because of the Windows OS)

gradle JavaEx- how to set MaxHeapSize?

I want to enlarge my java heap size.
using intellij on mac.
I have tried:
task BL_generate_dummy(type: JavaExec) {
JavaExec.setMaxHeapSize("4096")
classpath sourceSets.main.runtimeClasspath
main = "com.m.runners.BaselineGeneratorRunner"
}
and got this error:
* What went wrong:
A problem occurred evaluating root project 'RoutingRegression'.
> No signature of method: static org.gradle.api.tasks.JavaExec.setMaxHeapSize() is applicable for argument types: (java.lang.String) values: [4096]
Possible solutions: setMaxHeapSize(java.lang.String), getMaxHeapSize(), setMinHeapSize(java.lang.String), getMinHeapSize()
and also
JavaExec.setMaxHeapSize(4096)
JavaExec.maxHeapSize = 4096
what is the right syntax?
In general if I want to set a Java flag (not to main, but to running process arg). How do i set it in a gradle task?
task BL_generate_dummy(type: JavaExec) {
add '-Xmx4096m -Xms4096m' to the java flags
Think the JavaExec.set is superfluous.
Do
task BL_generate_dummy(type: JavaExec) {
maxHeapSize = "4096"
classpath sourceSets.main.runtimeClasspath
main = "com.m.runners.BaselineGeneratorRunner"
}
Btw in the current Gradle version (7.x) this will yield some deprecation warning . With Kotlin, change the mainClass from
main = "com.m.runners.BaselineGeneratorRunner"
to
mainClass.set("com.m.runners.BaselineGeneratorRunner")

Gradle task - pass arguments to Java application

I have a Java application that runs with a custom gradle task and the application requires some arguments upon being invoked. These are:
programName ( string | -f filename | -d key | -h)
Options:
string Message to be used.
-d key Use default messages, key must be s[hort], m[edium] or l[ong].
-f filename Use specified file as input.
-h Help dialog.
Gradle task looks like:
task run (type: JavaExec){
description = "Secure algorythm testing"
main = 'main.Test'
classpath = sourceSets.main.runtimeClasspath
}
I've tried running gradle run -h and it does not work.
Gradle 4.9+
gradle run --args='arg1 arg2'
This assumes your build.gradle is configured with the Application plugin. Your build.gradle should look similar to this:
plugins {
// Implicitly applies Java plugin
id: 'application'
}
application {
// URI of your main class/application's entry point (required)
mainClassName = 'org.gradle.sample.Main'
}
Pre-Gradle 4.9
Include the following in your build.gradle:
run {
if (project.hasProperty("appArgs")) {
args Eval.me(appArgs)
}
}
Then to run: gradle run -PappArgs="['arg1', 'args2']"
Since Gradle 4.9, the command line arguments can be passed with --args. For example, if you want to launch the application with command line arguments foo --bar, you can use
gradle run --args='foo --bar'
See Also Gradle Application Plugin
How to upgrade Gradle wrapper
If you want to use the same set of arguments all the time, the following is all you need.
run {
args = ["--myarg1", "--myarg2"]
}
Sorry for answering so late.
I figured an answer alike to #xlm 's:
task run (type: JavaExec, dependsOn: classes){
if(project.hasProperty('myargs')){
args(myargs.split(','))
}
description = "Secure algorythm testing"
main = "main.Test"
classpath = sourceSets.main.runtimeClasspath
}
And invoke like:
gradle run -Pmyargs=-d,s
You can find the solution in Problems passing system properties and parameters when running Java class via Gradle . Both involve the use of the args property
Also you should read the difference between passing with -D or with -P that is explained in the Gradle documentation
Of course the answers above all do the job, but still i would like to use something like
gradle run path1 path2
well this can't be done, but what if we can:
gralde run --- path1 path2
If you think it is more elegant, then you can do it, the trick is to process the command line and modify it before gradle does, this can be done by using init scripts
The init script below:
Process the command line and remove --- and all other arguments following '---'
Add property 'appArgs' to gradle.ext
So in your run task (or JavaExec, Exec) you can:
if (project.gradle.hasProperty("appArgs")) {
List<String> appArgs = project.gradle.appArgs;
args appArgs
}
The init script is:
import org.gradle.api.invocation.Gradle
Gradle aGradle = gradle
StartParameter startParameter = aGradle.startParameter
List tasks = startParameter.getTaskRequests();
List<String> appArgs = new ArrayList<>()
tasks.forEach {
List<String> args = it.getArgs();
Iterator<String> argsI = args.iterator();
while (argsI.hasNext()) {
String arg = argsI.next();
// remove '---' and all that follow
if (arg == "---") {
argsI.remove();
while (argsI.hasNext()) {
arg = argsI.next();
// and add it to appArgs
appArgs.add(arg);
argsI.remove();
}
}
}
}
aGradle.ext.appArgs = appArgs
Limitations:
I was forced to use '---' and not '--'
You have to add some global init script
If you don't like global init script, you can specify it in command line
gradle -I init.gradle run --- f:/temp/x.xml
Or better add an alias to your shell:
gradleapp run --- f:/temp/x.xml
You need to pass them as args to the task using project properties, something like:
args = [project.property('h')]
added to your task definition (see the dsl docs)
Then you can run it as:
gradle -Ph run

Gradle : Task dependency tree ignored?

I have a problem with gradle's task dependencies.
I have a version.properties file which must be cleared (on clean task) or filled (on war task) with a version info.
Therefore I set this dependency :
clean.dependsOn clearVersionProperties
and
processResources.dependsOn ([defaultValues,infoEnv])
compileJsps.dependsOn(classes, tomcatJasper, xmlModify)
war.dependsOn(compileJsps, svnRevision, writeVersionProperties)
My tasks have been externalized in a commons.gradle and look like this:
...
def writeVersionFile(String whatToWrite) {
File f = new File(project.webAppDirName+'/WEB-INF/version.properties');
if (f.exists()) { f.delete(); }
f = new File(project.webAppDirName+'/WEB-INF/version.properties');
FileOutputStream os = new FileOutputStream(f);
os.write(whatToWrite.getBytes());
os.flush();
os.close();
}
task clearVersionProperties() {
println "Clearing version file"
String whatToWrite = "version=#version#"
writeVersionFile(whatToWrite)
}
task writeVersionProperties(dependsOn: svnRevision) {
println "Writing version file"
String whatToWrite = "version="+project.ext.revision;
writeVersionFile(whatToWrite)
}
...
From my understanding clean will now call clearVersionProperties and war will call writeVersionProperties.
But when I execute a gradle clean, the reactor plan looks like this :
C:\devtools\....\branches\merge\Application>gradle -bbuild20.gradle clean -Ptomcat=7 -Ptarget=live
To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: http://gradle.org/
docs/2.0/userguide/gradle_daemon.html.
_______________________________________________________________________________
### building LIVE system
_______________________________________________________________________________
Clearing version file
Writing version file
JSP compilation...
TC7 Sources integrated
________________________________________________________
Compiling JSPs against Tomcat 7.0.11
________________________________________________________
:clearVersionProperties UP-TO-DATE
:clean UP-TO-DATE
BUILD SUCCESSFUL
Total time: 16.803 secs
Why are the tasks clearVersionProperties and writeVersionProperties executed, since they are bound to certain build phases? for example the task infoEnv is not executed, but - and this is really a problem - the task writeVersionProperties which only should be executed by the war task.
Any help appreciated!
in the meantime I found out why these tasks were fired :
I missed << after the task statement, so changing my two taks to
task clearVersionProperties() << {
println "Clearing version file"
String whatToWrite = "version=#version#"
writeVersionFile(whatToWrite)
}
task writeVersionProperties(dependsOn: [svnRevision]) << {
println "Writing version file"
String whatToWrite = "version="+project.ext.revision;
writeVersionFile(whatToWrite)
}
writeVersionProperties.mustRunAfter clearVersionProperties
This did the job.... I am not sure, if this is a bug, feature or side effect. But it seems to me the same utterly evil trap like forgetting () after a function.

Categories

Resources