Run Gradle build programmatically in a process

I am creating a function that runs the Gradle java command - sun.java.command in a child process passing environment variables needed for the execution (in the threads that in turn I join in the main process). Whenever I create the processes more than 1, it runs only one child process and gives the errors like

java.lang.OutOfMemoryError: Java heap space
        at java.base/java.util.ArrayList.<init>(ArrayList.java:154)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:39)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
java.io.EOFException
        at java.base/java.io.DataInputStream.readFully(DataInputStream.java:202)
        at org.gradle.internal.serialize.InputStreamBackedDecoder.readBytes(InputStreamBackedDecoder.java:69)
        at org.gradle.internal.serialize.AbstractDecoder.readBytes(AbstractDecoder.java:37)
        at org.gradle.internal.serialize.AbstractDecoder.readBinary(AbstractDecoder.java:44)
        at org.gradle.process.internal.worker.messaging.WorkerConfigSerializer.read(WorkerConfigSerializer.java:52)
        at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:80)
        at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

and sometimes only -

java.io.EOFException
        at java.base/java.io.DataInputStream.readInt(DataInputStream.java:397)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:38)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

The command I’m executing in child processes -

bin/java -Dorg.gradle.internal.worker.tmpdir=build/tmp/test/work -Dorg.gradle.native=false @/user/.gradle/.tmp/gradle-worker-classpath7183571986342629908txt -Xmx512m -Dfile.encoding=UTF-8 -Duser.country=IN -Duser.language=en -Duser.variant -ea worker.org.gradle.process.internal.worker.GradleWorkerMain 'Gradle Test Executor 1

I read the blog series to understand the Gradle build workflow, so definitely it’s not the right approach but how is it failing? Any way to achieve this programmatically.

Why do you try to run this manually?
If you want some environment variables set during testing, just configure the according Test task.

I need to to do this from a different package at runtime. So, cannot configure build.gradle manually.

You could use an init script to modify the build

Okay, I will try that…
Also, Is there a way to know the tasks user has specified in the command? Suppose user triggers - gradle clean test. Can we identify the clean and test somehow? Plus the cli args user would pass.

You can use gradle.startParameter to get that information, but you should usually not use it or base any logic on it.

You also have to be aware, that you get the tasks exactly like typed, so for example if the user call gw clea as it is unique enough, you will also get that clea, not clean.

Can’t use init script as I was to run build processes from javaagent. Seems like init script won’t have impact there. :confused:

Can we access gradle.startParameter from Gradle tooling API for current running build that user triggered with cli command ? Cannot find relevant documentation.

I’m not sure what you mean.
Neither what you mean with “run build processes from javaagent”,
nor about “accessing gradle.startParameter from Gradle tooling API”.
You use the tooling API to programmatically trigger a build or get information about a build.
If someone uses the CLI to run a build, the CLI will also use the tooling API to start that build iirc.
If you use the tooling API to run the build, you know exactly which tasks are requested as you specify which tasks to run.
From inside the build you can always use gradle.startParameter to get that information.

Acknowledged. Since I am creating a different package, the problem is I want to run the same command thrice that user is running with command-line args they passed and with value of an environment variable which I’m gonna pass. I won’t know the exact command user is passing in a single command.

Few things I tried -

  • Created a Gradle Plugin from where I can access the startParameter what has the tasks passed. Now the issue is I would want to access command line args user might have passed. Hence, creating the command is not scalable.
  • I’m trying to use GradleBuild task that I can run with startParameter instance. Can we run the task from init script or project type plugin?

It would be the best if could get command-line of the initial process from the daemon process.

I would not use GradleBuild tasks, they are legacy and not working with some things.
But you can probably just use the tooling API that is available with Gradle anyway, to do that maybe.

Hi @Vampire , apologies was been off for a while. I’ve restarted the work on this. By javaagent, I meant Instrumentation jar that we add in jvmargs. Refer, https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html

In the package I developed, I’m trying to run tasks based on some config parsed from a file as an array say xyz. I need to run the same tasks that user will pass through (gradle clean sampleTask --some-args) in parallel as many as the entries in xyz. I also need to make sure the my package again gets invoked.

Right now, what I was doing was to spawn different processes (gradle test command) for each xyz entry as child process (passing some environment variables to them). But unfortunately command is getting executed in an infinite loop :confused: . It was stopped based on the environment variable but that variable value is null after a build execution, mostly due to new environment getting spawned in an infinite loop.

I’m pretty aware what a Java agent is.
What I did not understand was why you would want to run a Gradle build from an Java agent.
But either way, it still is Java code, so you can still just use the tooling API to drive a build.

Ya, I got that. But the issue is I don’t have the tasks that user will run using CLI. That I get from gradle plugin events only. I’ll give it one more try.

How does the user give them?
And where / how does the agent run?

Thought it would be better to keep it in a chain. Will remove if from here. Thanks for the help.