Compilation using tooling API

If I have a multi project build (with projects a, b, c that depend on each other) and want to compile it through the tooling API then I can submit something like…
ProjectConnection#newBuild#forTasks("a:classes", "b:classes", "c:classes")
The downside of this is that I don’t seem to be able to link most of the ProgressListener events back to the original tasks. So I don’t know if I’m getting a progress update for task a:classes or b:classes
Is there a way to know that? I can filter on OperationType but not on the original task name.

If there isn’t a way to do this then I was thinking it’s best to split this out into 3 separate BuildLaunchers and then I can have 3 separate ProgressListener and I will know which event applies to which task.
But does that incur a performance penalty? If I fire off 3 BuildLaunchers and project a depends on project b depends on project c then how good is Gradle at knowing that that BuildLauncher for a and just wait on BuildLauncher b which can wait on BuildLauncher c. Or are these BuildLaunchers unaware of each other and will clash trying to compile the same thing?

Which ProgressEvents are you talking about specifically?
For TaskStartEvent for example you can do getDescriptor() which gives you a TaskOperationDescriptor from which you can get the full task path.

And no, I don’t think the build launchers would be aware of each other.
If you invoke them sequentially, they just run sequentially, if you run them in parallel, they would probably run in different daemons and most likely disturb each other.

1 Like

Let’s say that projectA is standalone and projectB depends on projectC

I run tasks [":projectA:classes", ":projectB:classes"]

I’ll get a progress event with taskpath of :projectC:compileJava.

This is running because B depends on C but I only know that because I know the project structure. I’ve got no way to work out here whether it’s running because of :projectA:classes or because of :projectB:classes. I can’t attribute that progress event to one of my original tasks.

Is it possible to work that out from the info in the event?

I have no idea, I don’t think so, but why should you actually care?
Also, if both, A and B depend on C, which would you then attribute C to and why?
It simply is a task that is necessary as prerequisite of another task and thus is run.

Because I want to report compile progress per project.

Even compiling 1 project using the :projectA:classes task, I’ll get these events in order…
:projectA:compileJava started
:projectA:compileJava SUCCESS
:projectA:processResources started
:projectA:processResources skipped
:projectA:classes started
:projectA:classes SUCCESS
:projectA:jar started
:projectA:jar SUCCESS

If compileJava or jar takes a long time then I can’t report that back to the user because the only events that I know that pertain to my request are the :projectA:classes ones.

It’s fine if it’s not possible - I can report only the :projectA:classes events, I was just hoping to include all the dependent events relevant to the original task, not just the original task events.

You can probably investigate the dependencies to find according project dependencies or something similar, but I think it is not at all trivial and most probably not worth the effort.

Btw. if you triggered the classes task, it is strange that jar task is executed too.
Unless your build configures something in that regards.
By default in a standard Java project, classes should just trigger compileJava and processResources: The Java Plugin

1 Like

To solve this, I’ve got all the tasks from SourceSet. e.g. SourceSet#getProcessResourcesTaskName and created a map of taskPath → SourceSet

Then when I run classes and testClasses for multiple projects all at once, it’s possible to use the above map to associate the progress reports with the correct SourceSet.

Also - I think the reason jar task is being called is because of dependent projects on Windows. I seem to remember reading somewhere that Gradle does this because the Jar filesystem is faster than NTFS for many classes files. The jar is then included on the dependent project’s classpath rather than the classes output dir. I maybe wrong but I don’t think I’ve configured anything weird around the jar task.

Then when I run classes and testClasses for multiple projects all at once, it’s possible to use the above map to associate the progress reports with the correct SourceSet.

I have no idea how that help in any way solve the problem, but well if you are happy, I am. :smiley:

Also - I think the reason jar task is being called is because of dependent projects on Windows. I seem to remember reading somewhere that Gradle does this because the Jar filesystem is faster than NTFS for many classes files. The jar is then included on the dependent project’s classpath rather than the classes output dir. I maybe wrong but I don’t think I’ve configured anything weird around the jar task.

No, 1. this performance difference can be true, but is nothing Gradle does automatically, you would still need to enable this and then it is also only for compilation classpaths: The Java Library Plugin. And 2. either way this would only be relevant if something that needs A is also built. Building the jar if you say classes is just a waste of time and Gradle does not do that unless you tell it to.