Витяг загальних методів із сценарію збірки Gradle


85

У мене є сценарій побудови 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, головне, для того, щоб додаткова збірка працювала правильно, знадобиться додаткова робота. Призначена абстракція полягає у використанні та повторному використанні Завдання s. Ви також можете створювати власні завдання . Можливо, вам варто розглянути можливість введення реалізацій, які ви зараз маєте в методи, у завдання.
Альпар

@Alpar та інші ; якій меті слугує створення чогось на кшталт a timestamp()або currentWorkingDirectory()методів як 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
Це справді трюк! Але у мене є питання з цього приводу: Як щодо методів, які щось повертають? Fe File foo(String f)стане ext.foo = { f -> ... }, чи можу я тоді просто зробити щось на зразок File f = foo(...):?
Pieter VDE

2
Очевидно, питання у моєму попередньому коментарі можливе. Тож дякую Петру, що відповів на це запитання!
Pieter VDE

1
@PeterNiederwieser Чому це не можливо? Gradle.org вважає інакше: docs.gradle.org/current/userguide/…
Ігор Ганапольський

1
@IgorGanapolsky дякую за посилання. Цікаво, як я можу використовувати значення, сформоване в окремому файлі збірки у gradle.build - таким чином, це було б дуже корисно :)
kiedysktos

@IgorGanapolsky Як посилання, яким ви поділились, може допомогти у контексті запитання про Пітера VDE?
t0r0X

157

Спираючись на відповідь Петра , ось як я експортую свої методи:

Зміст 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?
Ануп

1
@AnoopSS Ми додаємо два закриття до додаткових властивостей Gradle . Ці додаткові властивості об’єднані в об’єкт із назвою ext.
Маттіас Браун,

Чи можемо ми якось визначити значення як наш клас, який визначено у включеному файлі?
GarouDan

Можливо, є гарною ідеєю опублікувати окреме запитання з прикладом коду про це, @GarouDan.
Маттіас Браун,

7

Використовуючи Kotlin dsl, це працює так:

build.gradle.kts :

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

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

external.gradle.kts :

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

чудово, чи є спосіб поділитися актуальним типом? Ви в основному втрачаєте безпеку типу та допомогу компіляторів ... якщо ви можете поділитися класом, що містить ваші методи, тоді ви можете скористатися компілятором.
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))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.