Plugins often want to supply a default value for a property, but allow the user to override it.
Other plugins may want to supply a convention value for a property that overrides the original plugin's default but still allow the user to override it.
Both of these use cases can be very sensitive to ordering problems.
Simple default
Here's a simple example of a plugin supplying a task, configuring some defaults and a build script trying to override it.
mytask.prop ends up with the value "plugin value", which isn't what the build script author wanted or the plugin author intended. This leads some people to try to defer setting things:
Possible fix #1 in build script code:
apply plugin: 'myplugin' // OK, as long as this is never moved after the withType below.
tasks.withType(MyTask).configureEach {
prop.set("build script value")
}
Possible fix #2 in build script code, just slap a afterEvaluate in there:
tasks.register("mytask", MyTask) {
// OK, as long as prop isn't expensive to determine or require other things to be set first
if (prop.getOrNull() == null) {
prop.set("plugin value")
}
}
There may be some other clever things you could do in the plugin to ensure a particular "configure first" action happened before all others.
This works because the appropriate ordering is maintained, but has the same kind of ordering problems as the simple default. Depending on the ordering between myplugin, convention and the build script, you can get mytask.prop to have either "convention value" or "build script value". A poorly written convention plugin could force "convention value" or even let "plugin value" slip through as the default. If you imagine this combined with the possible fixes from above, it's easy to make a property that is difficult to configure properly.
defaults API
All of the sets from plugins above would be replaced with defaults (or better name):
Plugins often want to supply a default value for a property, but allow the user to override it.
Other plugins may want to supply a convention value for a property that overrides the original plugin's default but still allow the user to override it.
Both of these use cases can be very sensitive to ordering problems.
Simple default
Here's a simple example of a plugin supplying a task, configuring some defaults and a build script trying to override it.
myplugin
code:Build script code:
mytask.prop
ends up with the value "plugin value", which isn't what the build script author wanted or the plugin author intended. This leads some people to try to defer setting things:Possible fix #1 in build script code:
Possible fix #2 in build script code, just slap a
afterEvaluate
in there:Possible fix #3 in build script code, overkill/reconfigure the task in the execution phase:
Possible fix #1 plugin code:
There may be some other clever things you could do in the plugin to ensure a particular "configure first" action happened before all others.
Plugin default + convention default
myplugin
code:convention
code:Build script code:
This works because the appropriate ordering is maintained, but has the same kind of ordering problems as the simple default. Depending on the ordering between
myplugin
,convention
and the build script, you can getmytask.prop
to have either "convention value" or "build script value". A poorly writtenconvention
plugin could force "convention value" or even let "plugin value" slip through as the default. If you imagine this combined with the possible fixes from above, it's easy to make a property that is difficult to configure properly.defaults
APIAll of the
set
s from plugins above would be replaced withdefaults
(or better name):myplugin
code:convention
code:Build script code:
TBD fully flesh this out.