2013-04-25 27 views
16

Tôi đang viết một plugin gradle tùy chỉnh để xử lý một số công việc phức tạp mơ hồ và tôi đã gặp sự cố bực bội trong khi sử dụng các thuộc tính để định cấu hình một số tác vụ mà plugin áp dụng.Tiện ích mở rộng gradle có thể xử lý đánh giá lười biếng của một thuộc tính không?

apply plugin: myPlugin 

//Provide properties for the applied plugin 
myPluginProps { 
    message = "Hello" 
} 

//Define a task that uses my custom task directly 
task thisTaskWorksFine(type: MyTask) { 
    input = myPluginProps.message 
} 

//Define a plugin that will apply a task of my custom type 
class MyPlugin implements Plugin<Project> { 
    void apply(Project project) { 
     project.extensions.create('myPluginProps', MyPluginExtension) 

     project.task(type: MyTask, 'thisTaskWorksIncorrectly') { 
      input = project.myPluginProps.message 
     } 
    } 
} 

//The extension used by my custom plugin to get input 
class MyPluginExtension { 
    def String message 
} 

//The task used by both the standard build section and the plugin 
class MyTask extends DefaultTask { 
    def String input 

    @TaskAction 
    def action() { 
     println "You gave me this: ${input}" 
    } 
} 

Kết quả từ việc sử dụng tập tin này như sau:

$ gradle thisTaskWorksFine thisTaskWorksIncorrectly 
:thisTaskWorksFine 
You gave me this: Hello 
:thisTaskWorksIncorrectly 
You gave me this: null 

BUILD SUCCESSFUL 

Tôi coi đây là rất bất ngờ. Để tâm trí của tôi, việc áp dụng một nhiệm vụ từ các plugin và viết một trực tiếp nên kết quả trong cùng một đầu ra khi đưa ra cùng một đầu vào. Trong trường hợp này, cả hai nhiệm vụ đều được cung cấp myPluginProps.message làm đầu vào, nhưng tác vụ được áp dụng bởi plugin là tham lam và đánh giá thành null sớm. (Trong quá trình áp dụng giai đoạn?)

Giải pháp duy nhất tôi đã tìm thấy là sử dụng đóng cửa trong khối cấu hình các nhiệm vụ plugin như vậy:

//Define a plugin that will apply a task of my custom type 
class MyPlugin implements Plugin<Project> { 
    void apply(Project project) { 
     project.extensions.create('myPluginProps', MyPluginExtension) 

     project.task(type: MyTask, 'thisTaskWorksIncorrectly') { 
      input = { project.myPluginProps.message } 
     } 
    } 
} 

Đó giải quyết vấn đề thẩm định tham lam khá độc đáo trừ mà bây giờ nhiệm vụ tùy chỉnh phải được sửa đổi để mong đợi và xử lý việc đóng cửa. Nó không phải là khó khăn để làm, nhưng tôi không nghĩ rằng nó phải là trách nhiệm của nhiệm vụ để đối phó với việc đóng cửa, kể từ khi plugin là "đổ lỗi".

Tôi có đang sử dụng tiện ích không chính xác tại đây không? Hoặc là họ chỉ không đủ? Quan điểm chính thức có vẻ như là we should use extensions nhưng tôi chưa tìm thấy bất kỳ ví dụ nào mà tiện ích mở rộng có thể làm những gì tôi cần. Tôi có thể di chuyển về phía trước với việc sử dụng các bao đóng và viết một loạt các getters boilerplate mà đóng cửa eval và setters có thể xử lý các bao đóng và các loại bình thường, nhưng nó có vẻ rất chống lại triết lý của groovy và do đó gradle. Tôi sẽ rất hạnh phúc nếu có một cách mà tôi có thể sử dụng phần mở rộng và nhận được đánh giá lười biếng tự động.

Trả lời

12

Giải pháp thông thường cho vấn đề này là sử dụng ước lập bản đồ:

class MyPlugin implements Plugin<Project> { 
    void apply(Project project) { 
     project.extensions.create('myPluginProps', MyPluginExtension) 

     project.task(type: MyTask, 'thisTaskWorksIncorrectly') { 
      conventionMapping.input = { project.myPluginProps.message } 
     } 
    } 
} 

và sau đó trong nhiệm vụ:

class MyTask extends DefaultTask { 
    def String input 

    @TaskAction 
    def action() { 
     println "You gave me this: ${getInput()}" 
    } 

}

Xin lưu ý rằng tôi dứt khoát dùng getter cho input - ánh xạ quy ước sẽ không khởi động nếu bạn tham chiếu trực tiếp đến trường.

+0

Có sự khác biệt nào giữa bản đồ quy ước và quy ước không? Câu trả lời của bạn trông khá trơn, vì vậy tôi gần như chắc chắn sẽ sử dụng nó, nhưng một trong những devs lõi đã nói "Trong ngắn hạn, chỉ sử dụng phần mở rộng, không sử dụng công ước." Có lẽ tôi đã làm điều đó quá nghĩa đen. –

+2

[quy ước] (http://www.gradle.org/docs/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:convention) mà Peter đang đề cập là cơ chế cũ cho tiện ích. Sự khác biệt là bạn nhận được dsl ('myPluginProps {message =" Hello "}') miễn phí với các phần mở rộng và bạn không nhận được chúng với các quy ước.Các quy ước và ánh xạ quy ước là hai thứ khác nhau và ánh xạ quy ước được sử dụng trong nội bộ trong [mã gradle] (https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/groovy/org/gradle/ api/plugins/JavaPlugin.java # L131) rất nhiều. – erdi

+0

Tuyệt vời. Trong nghiên cứu của tôi, tôi đã né tránh mọi thứ đã đề cập đến quy ước từ, nhưng điều đó thật vội vàng. Cảm ơn vì lời khuyên! –

13

Câu trả lời của Peter trong câu hỏi của tôi here cho biết rằng tính năng conventionMapping chắc chắn sẽ biến mất. Tốt nhất là tránh nó.

Sử dụng afterEvaluate để giải quyết vấn đề cấu hình hoãn lại bị hoãn đã làm cho mã của tôi sạch hơn rất nhiều so với cách tiếp cận ConventionMapping.

class MyPlugin implements Plugin<Project> { 
    void apply(Project project) { 
     project.extensions.create('myPluginProps', MyPluginExtension) 

     project.afterEvaluate { 
      project.task(type: MyTask, 'thisTaskWorksIncorrectly') { 
       input = project.myPluginProps.message 
      } 
     } 
    } 
} 
Các vấn đề liên quan