Problems using other pre-compiled script plugins in a precompiled convention plugin

I’m unable to get a build working that uses pre-compiled script plugins and a pre-compiled convention plugin. I’ve constructed a simplified repo here: GitHub - fidothe/convention-plugin-example: Demonstrates a problem I'm having using gradle convention plugins with other precompiled script plugins

The idea is that the editorial-convention-plugin applies the com.saxonica.build.editorial plugin and then registers the tasks needed (which are defined in the com.saxonica.build.editorial plugin.

Currently gradle fails, complaining with:

> Task :buildSrc:generatePrecompiledScriptPluginAccessors FAILED

FAILURE: Build failed with an exception.

* Where:

Precompiled script plugin '/.../convention-plugin-example/buildSrc/src/main/kotlin/editorial-convention-plugin.gradle.kts' line: 1

* What went wrong:

Plugin [id: 'com.saxonica.build.editorial'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)

- Plugin Repositories (plugin dependency must include a version number for this source)

I am really baffled by this one. I can apply com.saxonica.build.editorial in a subproject build.gradle.kts without problem. Any pointers would be gratefully received…

That’s a mixture of chicken-and-egg problem and what-the-hell-are-you-doing problem. :smiley:

To build the accessors for a precompiled script plugin - just like with normal build scripts - the plugins { ... } block is extracted, applied to a dummy project and observed what it added to generate according type-safe accessors.

You can apply sibling precompiled script plugins, as for that there is special support, but you cannot apply normal binary plugins like that, as they do not exist yet and thus cannot be applied. A normal binary plugin you would need to apply the legacy way using apply(...).

But, your plugin does not do anything, and your plugin does not define those tasks.
You happen to have stored those task classes in the same source file as that no-op plugin,
but that does not make them related in any way at all, other than that they are in the same source file.

Applying that plugin, does not have any effect at all.

Well, if you would apply it in a build script where nothing else from that plugin project is applied, it would bring all the classes from that project on the classpath.

But applying it from a plugin also in that project is just useless as long as the apply method is empty, because as those classes are in the same project, they are anyway already on the classpath when your precompiled script plugin is applied.

Well, that’s par for the course :rofl:

That makes a lot of sense. It sounds more and more like adding .kt plugins in your buildSrc is just asking for trouble - you miss the magic you get with .kts and you don’t get the benefits of being discovered and loaded through traditional means (like a maven repo).

In the non-trivial build scripts this is drawn from, stuff does happen in the apply() method, mostly creating extension objects and setting default values, but the plugins are largely a file that contains a bunch of task classes…

I wonder if we’d be better off extracting the task classes from the plugin, and doing more plugin-y things there, like all the task definitions… probably wouldn’t need a separate convention plugin then…

Interesting. Thanks for the pointer about binary vs. pre-compiled script plugins (in my reading of the docs, the things about ‘binary plugins are distributed as JARs’ has been muddying the waters for me).

It sounds more and more like adding .kt plugins in your buildSrc is just asking for trouble - you miss the magic you get with .kts and you don’t get the benefits of being discovered and loaded through traditional means (like a maven repo).

I don’t think I can follow.
The only differences are the syntax.
The precompiled script plugins are basically just syntactic sugar over a normal binary plugin with the ID derived from package and filename.
But other than that, they should behave identical.

In the non-trivial build scripts this is drawn from, stuff does happen in the apply() method, mostly creating extension objects and setting default values, but the plugins are largely a file that contains a bunch of task classes…

No, the plugin is not a file that contains task classes.
The plugin happens to be stored in the same source file as those task classes, but they are independent of them, at least technically.
Or rather not more dependent than any other class in the same project.
You can still apply the plugin by type or also id in the pre-compiled script plugin, just not within its plugins { ... } block, but using the “traditional” apply(...), and thus not getting type-safe accessors.

Alternatively you could stuff those binary plugins in another project of the same build and add a dependency from the project with the precompiled script plugin onto the project with the binary plugin, because then chicken-and-egg is resolved as the project with the binary plugin is built first and can then be used in the plugins { ... } block of the precompiled script plugin I think.

I wonder if we’d be better off extracting the task classes from the plugin,

Well, as I said, whether those task files are in the same source file as the plugin or in separate files is totally irrelevant, there is no technical difference besides the file-information in the stacktrace / classfile

and doing more plugin-y things there, like all the task definitions… probably wouldn’t need a separate convention plugin then…

Yeah, well, that you have to know.
Both can make sense, depends strongly on details and needs. :slight_smile:

binary plugins are distributed as JARs

Well, the “binary plugins” term might also be used a bit inconsistently.
Actually after compiling a precompiled script plugin, it also is a binary plugin.
And a precompiled script plugin when compiled can as well be distributed as a JAR.
And both can also be used from an included build.
There is really not much difference except for the syntax you type.