DefaultSourceDirectorySet Alternative

I’ve been using DefaultSourceDirectorySet in my plugin for a while now, in order to add a source set extension for an Android plugin:

project.android.sourceSets.all { sourceSet ->
    sourceSet.extensions.create('svg', DefaultSourceDirectorySet, 'svg', project.fileResolver)
}

It looks like things have changed in Gradle 2.12 which now crashes when I use DefaultSourceDirectorySet, which is fine, since it is an internal API. (In particular, it gives the message “Could not create an instance of type org.gradle.api.internal.file.DefaultSourceDirectorySet_Decorated.”)

The question I have then is, what is the alternative? Do I need to implement my own SourceDirectorySet? Or is there some public way of doing this easily that I am just unaware of?

1 Like

That’s currently the way to go, yes.

Another option which still uses internal classes but is likely to be more ‘future proof’

SourceDirectorySetFactory factory = 
   project.gradle.services.get(SourceDirectorySetFactory)
DefaultSourceDirectorySet sds = factory.create("svg")

Wait, seriously? The best solution is for everyone to implement an interface with a couple dozen methods?

1 Like

Note that you don’t have to implement SourceDirectorySet. You can define an interface with just the API you care about yourself, like I did for instance in the Xtext plugin.

I currently don’t know of a plan to make the DefaultSourceDirectorySet of the current Gradle model public.

The new software model already provides a public API for defining custom LanguageSourceSets.

Then how to use this factory in place of DefaultSourceDirectorySet?

project.android.sourceSets.all { sourceSet ->
    sourceSet.extensions.add('svg', factory.create('svg'))
}
2 Likes

Another alternative, as described in Idiomatic Gradle, is to use some metaprogramming to work around it and maintain compatibility from Gradle 2.0 - 2.12. An example is here - https://github.com/ysb33r/gradle-mirah-plugin/blob/master/src/main/groovy/org/ysb33r/gradle/mirah/MirahSourceSet.groovy#L69

P.S Some self-promotion following: You can also read about this in the (free) sample version of Idiomatic Gradle at http://samples.leanpub.com/idiomaticgradle-sample.pdf (Just go to the Add SourceSet Support for JVM Language recipe).

I, personally, would maintain backwards compatability via:

import org.gradle.util.GradleVersion

boolean useFactory = GradleVersion.current().compareTo(GradleVersion.version("2.12")) >= 0 
project.android.sourceSets.all { sourceSet ->
    if (useFactory) {
        SourceDirectorySetFactory factory = project.gradle.services.get(SourceDirectorySetFactory)
        sourceSet.extensions.add('svg', factory.create('svg'))
    } else {
        sourceSet.extensions.create('svg', DefaultSourceDirectorySet, 'svg', project.fileResolver)
    }
}
1 Like

I was having this exact issue, but when I use this code snippet in either 2.12 or 2.13 I’m getting:

> No service of type SourceDirectorySetFactory available in GradleScopeServices.

Can anyone provide any help on this issue?

I found that in Gradle 4.10.2 SourceDirectorySetFactory is available
from project.services (ProjectScopeServices),
not project.gradle.services (GradleScopeServices).