Myles
Myles

Reputation: 21500

Create SourceSet style Syntax in custom gradle plugin

I am writing a little gradle plugin that needs to expose configuration for two source locations. I am presently doing this via a project extension and the consumer gradle file would have syntax like:

generator {
   idl {
       baseDir = "src"
       include = "*.idl"
       exclude = "**/.svn"
   }

   template {
       baseDir = "src"
       include = "*.template"
       exclude = "**/.svn"
   }
}

My first attempt at this was accomplished by having two properties on the extension class like so:

class GeneratorExtension {
    public static final NAME = "generator"

    private Project project

    GeneratorExtension(Project project) {
        this.project = project
    }

    @Input ConfigurableFileTree idl
    @Input ConfigurableFileTree template

    void idl(String dir, Closure closure) {
        idl = project.fileTree(dir, closure)
    }

    void template(String dir, Closure closure) {
        template = project.fileTree(dir, closure)
    }
}

Which changes the gradle file syntax to:

generator {
    idl (dir = "src") {
        include = "*.idl"
        exclude = "*"
    }

    template (dir = "src") {
        include = "*.template"
        exclude = ""
    }
}

Now this works, but it doesn't give me the clean usability I would prefer. I'm fairly new to both gradle and groovy, it looks like I might be able to accomplish what I want through the use of a DefaultNamedDomainObjectSet, but that references internal classes and so that's why I'm here.

What would be the correct way to add an extension uses FileTree, but keeps the clean consumer syntax?

Thanks in advance.

Upvotes: 2

Views: 674

Answers (1)

Myles
Myles

Reputation: 21500

Thanks to this and Peter's comment above (which means doubly thanks to Peter) I have come up with a solution. The introduction of the NamedDomainObjectContainer into my thinking allowed an even better syntax for the consumer.

Here's what I ended up with:

generator {
    idl {
        dir = 'src'
        include = "*.idl"
        exclude = "*"
    }

    templates {
        java {
            dir = 'src'
            include = '*.template'
        }

        javascript {
            dir = 'src'
            include = '*.template'
        }
    }
}

And the plugin code:

class GeneratorPlugin implements Plugin<Project> {
    private GeneratorExtension extension
    void apply(Project project) {
        def templates = project.container(FileTreeContainer)
        extension = project.extensions.create(GeneratorExtension.NAME, GeneratorExtension, project, templates)
        applyTasks(project)
    }

    void applyTasks(final Project project) {
        project.task('generateJava', type: GenerateJavaTask, group: 'Preprocess', description: 'Generate Java files based on provided IDL files and templates') { }
        project.task('generateJavascript', type: GenerateJavascriptTask, group: 'Preprocess', description: 'Generate Javascript files based on provided IDL files and templates') { }
    }
}

class GeneratorExtension {
    public static final NAME = "generator"

    private Project project
    @Input FileTreeContainer idl
    @Input NamedDomainObjectContainer<FileTreeContainer> templates

        GeneratorExtension(Project project, NamedDomainObjectContainer<FileTreeContainer> templates) {
            this.project = project
            idl = new FileTreeContainer("idl")
            this.templates = templates
        }

        void idl(Closure closure) {
            project.configure(idl, closure)
            idl.fileTree = project.fileTree(idl.dir) {
                include idl.include
                exclude idl.exclude
            }
        }

        void templates(Closure closure) {
            templates.configure(closure)
            String foo = "hello"
        }
    }

Upvotes: 2

Related Questions