Extraiga métodos comunes del script de compilación de Gradle


85

Tengo un script de compilación de Gradle ( build.gradle), en el que creé algunas tareas. Estas tareas consisten principalmente en llamadas a métodos. Los métodos llamados también están en el script de construcción.

Ahora, aquí está la situación:

Estoy creando una buena cantidad de scripts de compilación, que contienen diferentes tareas, pero utilizan los mismos métodos del script original. Por lo tanto, me gustaría extraer estos "métodos comunes" de alguna manera, para poder reutilizarlos fácilmente en lugar de copiarlos para cada nuevo script que cree.

Si Gradle fuera PHP, algo como lo siguiente sería ideal:

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

Pero, por supuesto, eso no es posible. ¿O es eso?

De todos modos, ¿cómo puedo lograr este resultado? ¿Cuál es el mejor método posible para hacer esto? Ya leí la documentación de Gradle, pero parece que no puedo determinar qué método será el más fácil y el más adecuado para esto.

¡Gracias por adelantado!


ACTUALIZAR:

Logré extraer los métodos en otro archivo.

(utilizando apply from: 'common-methods.gradle' ),

entonces la estructura es la siguiente:

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

Después de ejecutar una tarea de build.gradle, me encontré con un nuevo problema: aparentemente, los métodos no se reconocen cuando están encommon-methods.gradle .

¿Algunas ideas de como reparar esto?


¿Estás seguro de que necesitas escribir los métodos? Te perderías algunas de las ventajas de Gradle si escribes tus scripts de compilación en términos de métodos; lo más importante, será un trabajo adicional para que la compilación incremental funcione correctamente. La abstracción prevista es utilizar y reutilizar Task s. También puede crear tareas personalizadas . Quizás debería considerar poner las implementaciones que tiene ahora en métodos en tareas.
Alpar

@Alpar y otros ; para qué sirve hacer algo como a timestamp()o currentWorkingDirectory()métodos como task-s (por ejemplo). Las funciones de utilidad y cosas similares son nominalmente escalares: no serían tareas excepto que existen limitaciones en la reutilización de código incorporada con Gradle y la mayoría de los sistemas de compilación. Me gusta el mundo DRY donde puedo hacer una cosa UNA vez y reutilizarla. De hecho, extendiendo el ejemplo de @Pieter VDE, también uso un root.gradlepatrón " " para mi proyecto principal: el archivo build.gradle generalmente define algunos detalles del proyecto y luego solo apply ${ROOT}...
será el

Si necesita una forma centralizada de trabajar con propiedades, tal vez esta pregunta pueda ayudarlo: stackoverflow.com/questions/60251228/…
GarouDan

Respuestas:


76

No es posible compartir métodos, pero puede compartir propiedades adicionales que contengan un cierre, que se reduce a lo mismo. Por ejemplo, declare ext.foo = { ... }in common-methods.gradle, use apply from:para aplicar el script y luego llame al cierre con foo().


1
¡Realmente funciona! Pero tengo una pregunta sobre esto: ¿Qué hay de los métodos que devuelven algo? Fe File foo(String f)se convertirá ext.foo = { f -> ... }, ¿puedo hacer algo como File f = foo(...):?
Pieter VDE

2
Aparentemente, la pregunta de mi comentario anterior es posible. ¡Así que gracias Peter, por responder a esta pregunta!
Pieter VDE

1
@PeterNiederwieser ¿Por qué no es posible? Gradle.org piensa lo contrario: docs.gradle.org/current/userguide/…
IgorGanapolsky

1
@IgorGanapolsky gracias por el enlace. Me pregunto cómo puedo usar un valor generado en un archivo de compilación separado en gradle.build; de esta manera sería muy útil :)
kiedysktos

@IgorGanapolsky ¿Cómo debería ayudar el enlace que compartiste en el contexto de la pregunta de Peter VDE?
t0r0X

157

Construyendo sobre la respuesta de Peter , así es como exporto mis métodos:

Contenido de 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
}

Y así es como uso esos métodos en otro script:

// 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)
}

Aquí encontrará más información sobre la conversión de métodos a cierres en Groovy.


¿Hay alguna razón específica para usar el nombre de cierre como ext?
Anoop

1
@AnoopSS Agregamos los dos cierres a las propiedades adicionales de Gradle . Estas propiedades adicionales se agrupan en un objeto llamado ext.
Matthias Braun

¿Podemos, de alguna manera, convertir el valor como una clase nuestra, que está definida en el archivo incluido?
GarouDan

Probablemente sea una buena idea publicar una pregunta separada con código de ejemplo sobre esto, @GarouDan.
Matthias Braun

7

Usando el dsl de Kotlin funciona así:

build.gradle.kts :

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

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

external.gradle.kts :

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

genial, ¿hay alguna manera de compartir el tipo actual? básicamente estás perdiendo la seguridad de tipos y los compiladores ayudan ... si pudieras compartir la clase que contiene tus métodos, entonces podrías hacer uso del compilador.
vach

0

Otro enfoque para Kotlin DSL podría ser:

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))
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.