Thanks for the link. I checked the example and based on it I tried to implement similar logic that I posted above. But Still no luck.
apply plugin: DocumentationPlugin
publisher {
info {
name 'Publisher'
}
books {
quickStart {
title = 'Quick Start'
sourceFile = file('src/docs/quick-start')
}
userGuide {
}
developerGuide {
}
}
}
task books << {
publisher.books.each { book ->
println "$book.name -> Title: $book.title, Source File: $book.sourceFile"
}
}
class DocumentationPlugin implements Plugin<Project> {
void apply(Project project) {
def publisher = project.extensions.create('publisher', Publisher)
publisher.extensions.create('info', PublisherInfo)
def books = project.container(Book)
books.all { book ->
println "$book.name -> Title: $book.title, Source File: $book.sourceFile"
// expect to create tasks for books and setup these tasks based on the book properties
sourceFile = project.file("src/docs/$name")
}
publisher.extensions.books = books
}
}
class PublisherInfo {
def name
}
class Publisher {
}
class Book {
final String name
String title
File sourceFile
Book(String name) {
this.name = name
}
}
In above code I am trying to create set of the tasks and configure them based on DSL. I can create them based on the name however can’t configure them as properties for the Books are null. They are only available when tasks run which in my case is to late.
Thanks for quick replay I think my last example was really unfortunate and didn’t present what I am trying to achieve. Hopefully this one will present the problem that I am struggling with.
apply plugin: DocumentationPlugin
publisher {
info {
name 'Publisher'
}
books {
quickStart {
title = 'Quick Start'
}
userGuide {
title = 'User Guide'
}
developerGuide {
title = 'Developer Guide'
}
}
}
class DocumentationPlugin implements Plugin<Project> {
void apply(Project project) {
def publisher = project.extensions.create('publisher', Publisher)
def publisherInfo = publisher.extensions.create('info', PublisherInfo)
def books = project.container(Book)
books.all { book ->
println "Creating task $book.name -> Title: $book.title, "
project.tasks.create("displayBook${book.name.capitalize()}", DisplayBook) {
publisherName = publisherInfo.name
title = book.title
}
}
publisher.extensions.books = books
}
}
class PublisherInfo {
String name
}
class Publisher {
}
class Book {
final String name
String title
Book(String name) {
this.name = name
}
}
class DisplayBook extends DefaultTask {
String publisherName
String title
@TaskAction
def displayBook() {
println "$name -> Title: $title, Publisher : $publisherName"
}
}
I am trying to create a task that will use DSL to sets itself. Based on the DSL also it will create a list of the tasks. If you run following code you will get following list of the tasks:
‘books.all’ fires whenever a new book has been added to the container, but before the book has been configured. You need to take additional measures to defer configuration of the task, such as ‘doFirst {}’, convention mapping, or a similar technique. As this is a common question, you should find more on this on the forums and on Stack Overflow.
I just got this working with convention mapping but it requires changing tasks to work with getters. It is not a problem but one have to remember to access properties through getters.
Also noticed that if I defer tasks creation to the ‘project.afterEvaluate’ method everything works correctly. I haven’t seen this being suggested anywhere.
Is there any particular reason why it is not being suggested as an option ?
Example below:
apply plugin: DocumentationPlugin
publisher {
info {
name 'Publisher'
}
books {
quickStart {
title = 'Quick Start'
}
userGuide {
title = 'User Guide'
}
developerGuide {
title = 'Developer Guide'
}
}
}
class DocumentationPlugin implements Plugin<Project> {
void apply(Project project) {
def publisher = project.extensions.create('publisher', Publisher)
def publisherInfo = publisher.extensions.create('info', PublisherInfo)
def books = project.container(Book)
project.afterEvaluate({
println "After evaluation"
books.all { book ->
println "Creating task $book.name -> Title: $book.title, "
project.tasks.create("displayBook${book.name.capitalize()}", DisplayBook) {
publisherName = publisherInfo.name
title = book.title
}
}
})
publisher.extensions.books = books
}
}
class PublisherInfo {
String name
}
class Publisher {
}
class Book {
final String name
String title
Book(String name) {
this.name = name
}
}
class DisplayBook extends DefaultTask {
String publisherName
String title
@TaskAction
def displayBook() {
println "$name -> Title: ${title}, Publisher : ${publisherName}"
}
}
Also noticed that if I defer tasks creation to the project.afterEvaluate method everything works correctly. I haven’t seen this being suggested anywhere. Is there any particular reason why it is not being suggested as an option ?
It’s often suggested as an option, but like other options, it has its limitations. For example, you can run into problems when one property depends on another property set in ‘afterEvaluate’, because you can’t control the order of ‘afterEvaluate’ callbacks. Also it’s difficult to test.
Note that convention mapping isn’t considered a public API. That said, currently all available options have their drawbacks. Fortunately, a new solution is in the works.