Move the buildscript block into a plugin..?

Due to very stringent conventions on our part many aspects of our builds are very repetetive. We would like to move everything into plugins used by all projects.

However we are struggeling to move parts of the buildscript{} block into plugins. Here is our settings.gradle.kts (or build.gradle.kts) we want to use for all projects:

buildscript {
dependencies {
classpath(files(“/mnt/data/common/bin”)) // where our plugin classes reside
}
}
apply {
plugin(“com.example.CommonInitPlugin”)
}

However it seems to be impossible to add (e.g. other plugin dependencies) to the buildscript: Cannot change dependencies of configuration ‘:classpath’ after it has been resolved.

How the code that fails looks like:

ScriptHandler buildscript = settings.getBuildscript(); // or project.getBuildscript(); in case we used either build.gradle.kts instead of settings.gradle.kts
buildscript.getDependencies().add(new DefaultExternalModuleDependency(“com.android.tools.build”, “gradle”, “3.2.0”));

Any idea how to work around this problem?

The buildscript block configures the classpath used for the rest of the script. The buildscript block itself shouldn’t be translated to the plugin. The plugin should just be performing the configuration that occurs in the rest of the script. Other dependencies of the plugin should be just that, dependencies of the plugin project, not configuration performed by the plugin itself. Once the plugin code executes, it’s too late. Those dependencies should be specified in the build file of the plugin.

Then at the very least there should be an option to allow people to “include” code blocks defined in other files verbatim into your settings.gradle and build.gradle.

// build.gradle:

include(“…/…/buildscriptblock.gradle”)

include(“/mnt/data/pool/common.gradle”)

The performance impact to parse for includes and paste them in would be basically zero (I did some tests).

Theoretically such an “include-hack” exists: Reuse of buildscript block - #6 by Dieter_K1 but in my case (I can go into details) it is not applicable.

At the moment I am duplicating a lot of build script code that could reside in a single file which I include in all my scripts. Moving the buildscript block into a plugin was my only hope to get a properly working version of verbatim includes.

You absolutely have this ability for everything except the buildscript block. The buildscript block is special because its only purpose is to specify how to resolve dependencies that should be on the classpath for the execution of the rest of the build script.

There’s a significant conceptual difference between I don’t want to duplicate the contents of the buildscript block that should be the same between several files in the build (deduplication) and the chicken/egg problem of I want a plugin on my classpath that executes code to modify the classpath that had be resolved in the first place to execute the plugin.

Your stated problem of wanting the plugin to provide additional plugin dependencies on the classpath is extremely common. You just don’t solve it with code in the plugin to mutate buildscript because that’s too late in the lifecycle.

When I was talking about configuration ‘:classpath’, I was talking about the classpath of the buildscript block. Basically I would be happy with one of two options:

  1. true (non hacky) verbatim includes of the buildscript block from buildscriptblock.gradle
  2. manipulation of the buildscript-block-classpath in my local plugin

At the moment there is no way to avoid duplication of the information included in the buildscript block.

There is this workaround: Reuse of buildscript block but my problem is, it only works for build.gradle and you cannot include the same file in another project that needs to use a settings.gradle and have the buildscript-block in settings.gradle since this hacky solution uses project.buildscript and project does not exist in settings.gradle.

I was hoping there would be a way to avoid buildscript-block duplication. It seems there isn’t.