แยกวิธีการทั่วไปจากสคริปต์สร้าง Gradle


86

ฉันมีสคริปต์สร้าง Gradle ( build.gradle) ซึ่งฉันสร้างงานบางอย่าง งานเหล่านี้ส่วนใหญ่ประกอบด้วยการเรียกใช้เมธอด วิธีการที่เรียกว่ายังอยู่ในสคริปต์การสร้าง

ตอนนี้นี่คือสถานการณ์:

ฉันกำลังสร้างบิลด์สคริปต์จำนวนพอสมควรซึ่งมีงานที่แตกต่างกัน แต่ใช้วิธีการเดียวกันจากสคริปต์ดั้งเดิม ดังนั้นฉันต้องการแยก "วิธีการทั่วไป" เหล่านี้ด้วยวิธีใดวิธีหนึ่งดังนั้นฉันจึงสามารถใช้ซ้ำได้อย่างง่ายดายแทนที่จะคัดลอกสำหรับสคริปต์ใหม่แต่ละรายการที่ฉันสร้างขึ้น

หาก Gradle เป็น PHP สิ่งต่อไปนี้จะเหมาะ:

//script content
...
require("common-methods.gradle");
...
//more script content

แต่แน่นอนว่าเป็นไปไม่ได้ หรือว่า?

อย่างไรก็ตามฉันจะบรรลุผลลัพธ์นี้ได้อย่างไร? วิธีใดเป็นวิธีที่ดีที่สุดในการดำเนินการนี้ ฉันได้อ่านเอกสาร Gradle แล้ว แต่ดูเหมือนจะไม่สามารถระบุได้ว่าวิธีใดจะง่ายที่สุดและเหมาะสมที่สุดสำหรับสิ่งนี้

ขอบคุณล่วงหน้า!


อัพเดท:

ฉันจัดการแยกวิธีการในไฟล์อื่นแล้ว

(ใช้apply from: 'common-methods.gradle'),

ดังนั้นโครงสร้างจึงเป็นดังนี้:

parent/
      /build.gradle              // The original build script
      /common-methods.gradle     // The extracted methods
      /gradle.properties         // Properties used by the build script

หลังจากดำเนินการงานbuild.gradleแล้วฉันได้พบกับปัญหาใหม่: ดูเหมือนว่าเมธอดจะไม่ได้รับการยอมรับเมื่อเข้าcommon-methods.gradleมา

มีแนวคิดในการแก้ไขอย่างไร


แน่ใจหรือว่าต้องเขียนวิธีการเลย? คุณจะพลาดสิ่งดีๆของ Gradle หากคุณเขียนบิลด์สคริปในแง่ของวิธีการที่สำคัญที่สุดคือต้องใช้เวลาเพิ่มขึ้นเพื่อให้บิลด์ที่เพิ่มขึ้นทำงานได้อย่างถูกต้อง สิ่งที่เป็นนามธรรมที่ตั้งใจไว้คือการใช้และกลับมาใช้Task s นอกจากนี้คุณยังสามารถสร้างงานที่กำหนดเอง บางทีคุณควรพิจารณาการนำวิธีการที่คุณมีอยู่มาใช้ในงาน
Alpar

@Alpar และอื่น ๆ ; จุดประสงค์อะไรที่ทำขึ้นเช่น a timestamp()หรือcurrentWorkingDirectory()method as task-s (ตัวอย่าง) ฟังก์ชันยูทิลิตี้และสิ่งที่คล้ายคลึงกันเป็นสเกลาร์ในนาม - จะไม่เป็นงานยกเว้นว่ามีข้อ จำกัด ในการใช้โค้ดซ้ำในตัว Gradle และระบบบิลด์ส่วนใหญ่ ฉันชอบโลกที่แห้งแล้งที่ฉันสามารถทำสิ่งหนึ่งครั้งและนำกลับมาใช้ใหม่ได้ ในความเป็นจริงการขยายตัวอย่างของ @Pieter VDE ฉันยังใช้root.gradleรูปแบบ "" สำหรับโปรเจ็กต์หลักของฉันด้วยเช่นกันไฟล์ build.gradle มักจะกำหนดเฉพาะโปรเจ็กต์บางอย่างจากนั้นก็แค่apply ${ROOT}...
จะ

หากคุณต้องการวิธีการทำงานร่วมกับคุณสมบัติจากส่วนกลางคำถามนี้อาจช่วยคุณได้: stackoverflow.com/questions/60251228/…
GarouDan

คำตอบ:


76

เป็นไปไม่ได้ที่จะแบ่งปันวิธีการ แต่คุณสามารถแบ่งปันคุณสมบัติพิเศษที่มีการปิดซึ่งทำให้เกิดสิ่งเดียวกันได้ ยกตัวอย่างเช่นการประกาศext.foo = { ... }ในcommon-methods.gradleการใช้งานที่จะใช้สคริปต์แล้วโทรปิดด้วยapply from:foo()


1
มันเป็นเคล็ดลับแน่นอน! แต่ฉันมีคำถามเกี่ยวกับเรื่องนี้: วิธีการคืนบางสิ่งบางอย่าง? เฟFile foo(String f)จะกลายเป็นext.foo = { f -> ... }ฉันจะทำอะไรแบบนี้ได้File f = foo(...)ไหม?
Pieter VDE

2
เห็นได้ชัดว่าคำถามในความคิดเห็นก่อนหน้าของฉันเป็นไปได้ ขอบคุณปีเตอร์ที่ตอบคำถามนี้!
Pieter VDE

1
@PeterNiederwieser ทำไมถึงไม่ได้ Gradle.org คิดเป็นอย่างอื่น: docs.gradle.org/current/userguide/…
IgorGanapolsky

1
@IgorGanapolsky ขอบคุณสำหรับลิงค์ ฉันสงสัยว่าฉันจะใช้ค่าที่สร้างขึ้นในไฟล์ build แยกต่างหากใน gradle.build ได้อย่างไร - วิธีนี้จะมีประโยชน์มาก :)
kiedysktos

@IgorGanapolsky ลิงก์ที่คุณแชร์จะช่วยในบริบทของคำถาม Peter VDE ได้อย่างไร
t0r0X

161

จากคำตอบของ Peterนี่คือวิธีที่ฉันส่งออกวิธีการของฉัน:

เนื้อหาของhelpers/common-methods.gradle:

// Define methods as usual
def commonMethod1(param) {
    return true
}
def commonMethod2(param) {
    return true
}

// Export methods by turning them into closures
ext {
    commonMethod1 = this.&commonMethod1
    otherNameForMethod2 = this.&commonMethod2
}

และนี่คือวิธีที่ฉันใช้วิธีการเหล่านั้นในสคริปต์อื่น:

// Use double-quotes, otherwise $ won't work
apply from: "$rootDir/helpers/common-methods.gradle"

// You can also use URLs
//apply from: "https://bitbucket.org/mb/build_scripts/raw/master/common-methods.gradle"

task myBuildTask {
    def myVar = commonMethod1("parameter1")
    otherNameForMethod2(myVar)
}

ข้อมูลเพิ่มเติมเกี่ยวกับการแปลงวิธีการปิดใน Groovy


มีเหตุผลเฉพาะในการใช้ชื่อการปิดเป็น ext หรือไม่?
Anoop

1
@AnoopSS เราได้เพิ่มสองปิดการคุณสมบัติพิเศษของ Gradle extคุณสมบัติพิเศษเหล่านี้จะถูกรวมอยู่ในวัตถุที่เรียกว่า
Matthias Braun

เราสามารถโยนค่าเป็นคลาสของเราซึ่งกำหนดไว้ในไฟล์ที่รวมได้หรือไม่?
GarouDan

อาจเป็นความคิดที่ดีที่จะโพสต์คำถามแยกต่างหากพร้อมรหัสตัวอย่างเกี่ยวกับเรื่องนี้ @GarouDan
Matthias Braun

7

การใช้Kotlin dslมันใช้งานได้ดังนี้:

build.gradle.kts :

apply {
  from("external.gradle.kts")
}

val foo = extra["foo"] as () -> Unit
foo()

ภายนอก.gradle.kts :

extra["foo"] = fun() {
  println("Hello world!")
}

1
มีวิธีที่ดีในการแบ่งปันประเภทแอคชูออลหรือไม่? โดยพื้นฐานแล้วคุณกำลังสูญเสียความปลอดภัยประเภทและความช่วยเหลือของคอมไพเลอร์ ... ถ้าคุณสามารถแชร์คลาสที่มีวิธีการของคุณคุณก็สามารถใช้คอมไพเลอร์ได้
vach

0

อีกแนวทางหนึ่งสำหรับ Kotlin DSL อาจเป็น:

my-plugin.gradle.kts

extra["sum"] = { x: Int, y: Int -> x + y }

settings.gradle.kts

@Suppress("unchecked_cast", "nothing_to_inline")
inline fun <T> uncheckedCast(target: Any?): T = target as T

apply("my-plugin.gradle.kts")

val sum = uncheckedCast<(Int, Int) -> Int>(extra["sum"])

println(sum(1, 2))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.