I have a buildservice (i.e. singleton) Map which h...
# plugin-development
l
I have a buildservice (i.e. singleton) Map which holds some state for use by all modules in a build. It should be configured once before the first project in the reactor is executed, by adding implementations to the buildservice Map. These implementations should be used in all modules of the build. Now … 1. What is the idiomatic Gradle way to populate the buildservice Map (once per build and before any modules are actually built, because its state will be used by a task in every module)? 2. Stashing the population into a plugin seems incorrect, because it is applied in every project. 3. Applying a BuildOperationListener could be a good way, but … how can I access implementations within - say - buildSrc to populate the buildservice map with? 4. Are there idiomatic examples of how to configure buildServices before the build starts? I may be poor at finding information in the gradle docs, but this seems … not a frequent type of task to solve.
v
Not fully sure what you mean, but is maybe a shared build service what you are after? Sounds like it.
l
Yes. And assuming I would like to configure it with objects created in the repo (typically created in the buildSrc) what would be the idiomatic way to access it?
An external repo contains the build service, and it is used by tasks created by a plugin. But i Want to populate the shared build service once, and before any Project is built.
What is the idiomatic way to do That?
v
Probably depends on the details. If you for example know the plugin will also be applied to the root project, you could for example init it there. Or you could maybe create your own build service that configures that other build service.
l
If I picked the option to use a local build service to initialize the other build service, where would I create the local build service to have it run exactly once and before the build started?
I would like to avoid having it done in the root project if possible
Can I avoid having to create an othewise empty plugin, for example?
v
A build service is scoped to one build execution, so if you do the configuration for example in its constructor, it will be done at most once during a given build. How to ensure it is done, again depends on the details. If you have an own plugin that is applied to the respective projects, you can for example register the build service there and immediately
get()
it, so that it gets initialized. Or you could declare all tasks to "use" the service, or you could register it as operation completion listener.
l
… “to have it run exactly once and before the build started” …
Your approach sounds like it (i.e. a populate-the-existing-build-service) will be called once per module.
Or am I missing something?
v
As I said, a build service is scoped to one build execution. Even if you register it 30 times, it will only be created at most once during one build run.
l
Yes, the (empty) build service instance will be a singleton, declared in an external repo and instantiated in the local repo. Fine. However, I would like the population/configuration of the build service instance do be done in the local repo. (Like populating a Map). Once, and before the build begins (i.e. before any project build is executed). I would like to avoid having the population method being called within each project in the local repo.
If i do that in a build service too, as you suggested above, where do I invoke that configure-the-build-service-buildservice?
v
Again, the population of the other build service's properties would be done in the constructor of your own build service and that service your can safely register in all modules, as it still will be created only once
l
Oki. So using a plugin which only creates and configures the buildservice, then?
That is doable, of course.
Is that, then, the idiomatic way to configue a build service defined in another repo? I’m after a recommended and documented pattern here, so knowledge can be spread within the organisation on how to treat and configure custom build services - and backed by Gradle’s best practises
v
I'm not the authority to declare anything idiomatic or not. I'm just a fellow user offering my expertise. 🙂 I'm not sure whether there is an "idiomatic" way to configure the build service of some 3rd party plugin, because I think is very uncommon per-se to do that. A build service is most often more an implementation detail of a plugin and not something the plugin consumers should care about.
l
Don't get me wrong, @Vampire. I appreciate your advice and your insights. What I am after is a documented recommendation and discussion from Gradle on the recommended patterns for several concepts (such as build services), as I am trying to train and inform our Platform and Build engineers. I simply cannot find something which describes how certain concepts should be used to create plugins which use facilities such as build cache & build services in an optimal/suggested/supported/recommended way. I can find descriptions on what they are, and I can - of course - read the source code to see implementation details of them. But Gradle contains many facilities which could be used to - say - hold shared state for an entire build, and I find it difficult to dig out how some of them are intended to be used ("idiomatic" usage in my book). Hence my stress on the intention, because if I interpret you correctly, the intended use for a build service/singleton which is defined in an external plugin is as follows:
1. Find the build service you need to configure in an external repo/plugin JAR 2. In buildSrc in your own repo, create a dependency on the JAR containing the desired build service. 3. In buildSrc in your own repo, create a custom plugin which registers another build service. 4. In the constructor of your local build service, inject all build services you want to configure - and perform the configuration of the desired build service from (1)
That pattern is - as far as I can tell - not described in any Gradle documentation. It is certainly doable, although not completely intuive.
v
Yeah, I fully understood what you are after. But I'm not aware of any documentation containing what you are after (which of course does not mean there is none). Maybe also because as I said, I think the use-case is very uncommon and non-idiomatic in itself. If you want such a thing added to the documentation, you probably need to open a documentation improvement request in GitHub, to get an official documented way or at least by Gradle folks reviewed way. Btw. also keep in mind, that not everything you find in the official docs might be the recommended or idiomatic way (at least in the meantime). As with every documentation, the moment it is written, it is outdated. :-D So there might well be things that maybe were idiomatic but are not anymore and sometimes different parts also contradict each other. The
init
task for example when generating convention plugins nowadays uses an included build, not
buildSrc
which is often used in the docs, so I would say it is at least questionable which is the recommended or idiomatic way.
l
Thanks, @Vampire. 🙂
👌 1