Best ways of "extending" a plugin?

I am trying to understand the best way to codify default logic for my team’s use of a plugin. In particular my target is the nebula rpm plugin which is documented here.

As described in the linked documentation, this plugin allows defining a task in which many values pertinent to rpm creation are settable, for example:

task fooRpm(type: Rpm) {
    packageName 'foo'
    version '1.2.3'
    release 1
    arch I386
    os LINUX
    user 'xyz'
    permissionGroup 'xyz' 

    installUtils = file('scripts/rpm/utils.sh')
    preInstall file('scripts/rpm/preInstall.sh')
    postInstall file('scripts/rpm/postInstall.sh')
    preUninstall file('scripts/rpm/preUninstall.sh')
    postUninstall file('scripts/rpm/postUninstall.sh')

etc.

In my situation, some of these values would be common to ALL rpms I want to create with this plugin, others would be common to a subset of all rpms, while still others might be specific to a single rpm build.

I began by defining ext properties for some of the common values. Then I can code the value setters to use these properties and copy these declarations from one build script to another.

But this is obviously only a halfway measure. What I want is a plugin (“extending” nebula rpm) where all these things are predefined. Then this plugin only need be applied saving all the error-prone copying. As for “flavors” i.e. for repeated “types” of builds which recur frequently with the same parameters, I see this could be handled either with multiple plugins or possibly a single plugin where a “type” parameter defines which flavor (i.e. set of values) would be chosen.

Is creating plugins the way to go for this need? Or is there a better way? Is there a standard mechanism for “extending” a plugin this way or some samples or best-practice documentation for doing this?

Thanks in advance.

In this case, what you want is what is referred to as “plugin composition”. You would have your own plugin that first applies the rpm plugin (using project.apply()). Then you would layer your own conventions on top of that. Typically this would take the form of configuration rules applied against task types (i.e. project.tasks.withType(Rpm) { ... }) or tasks matching a condition (i.e. project.tasks.matching { ... }).

As far as documentation, there aren’t any samples out there, but looking at other plugins is probably the best way to understand. This topic is touched on in Ben Muschko’s talk at SpringOne last year on plugin best practices. His docker plugin is a pretty good example of this pattern.

Thanks, yes, that’s exactly what I want to do. I just didn’t know the name for it, not that there’s that much information available on it.

Unfortunately, corporate firewall blocks me from watching Ben Muschko’s talk, and even without the firewall, there is some sort of issue reaching it which may be what triggered the corporate block. Is it available anywhere else? Or can it be made so?

Failing that, I will soldier on using the docker example.

Thanks, again.

OK, have seen Ben’s talk and looked at the example. But, a question for you:

line 64-66 of
is

dockerExtension.metaClass.javaApplication = { Closure closure ->
             ConfigureUtil.configure(closure, dockerJavaApplication)
}

However, org.gradle.util.ConfigureUtil no longer seems to be part of the latest version of the Gradle API. What replaced it?

Thanks.

Wow! Looks like a bug in the document generator. The class still exists in the distribution, but the entire org.gradle.util package is missing from javadoc and groovydoc and the search function only finds something from v0.7.

Classes in org.gradle.util are not a part of the public API. This means these classes could change at any time without warning, so they really shouldn’t be used unless there’s just not a better solution.

Thanks, yeah, I posted this as a “bug” but was told that internal classes should not be used. And the use of it in this sample really doesn’t have anything to do with plugin composition.

Anyway, I am trying to debug a problem now with my plugin composition. One property is failing to be implemented properly. I am setting these properties inside my plugin. According to logs I write at configure time, the “os” property is being mapped correctly, yet after the build has run, the RPM is rejected as being of unknown type. if instead of doing this I set the os property in my build script (as in the example above) , then all is well.

So my basic newbie question is this: in order to debug this, how, using the api, can I retrieve the collection of all the settings in a doFirst() call in my build script to see what properties the build will be working with. What methods are available on Task will pull this collection of values?