Estrai metodi comuni dallo script di build Gradle


86

Ho uno script di build Gradle ( build.gradle), in cui ho creato alcune attività. Queste attività consistono principalmente in chiamate di metodo. I metodi chiamati sono anche nello script di compilazione.

Ora, ecco la situazione:

Sto creando una discreta quantità di script di compilazione, che contengono attività diverse, ma utilizzo gli stessi metodi dello script originale. Pertanto, vorrei estrarre questi "metodi comuni" in qualche modo, in modo da poterli riutilizzare facilmente invece di copiarli per ogni nuovo script che creo.

Se Gradle fosse PHP, qualcosa di simile sarebbe l'ideale:

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

Ma ovviamente non è possibile. O è?

Comunque, come posso ottenere questo risultato? Qual è il miglior metodo possibile per farlo? Ho già letto la documentazione di Gradle, ma non riesco a determinare quale metodo sarà il più semplice e il più adatto per questo.

Grazie in anticipo!


AGGIORNARE:

Sono riuscito a estrarre i metodi in un altro file

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

quindi la struttura è la seguente:

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

Dopo aver eseguito un'attività da build.gradle, mi sono imbattuto in un nuovo problema: apparentemente, i metodi non vengono riconosciuti quando sono presenti common-methods.gradle.

Qualche idea su come risolverlo?


Sei sicuro di dover scrivere i metodi? Ti perderesti alcune delle chicche di Gradle se scrivi i tuoi script di compilazione in termini di metodi, soprattutto ci vorrà del lavoro extra per far funzionare correttamente la build incrementale. L'astrazione prevista è quella di utilizzare e riutilizzare le attività . Puoi anche creare attività personalizzate . Forse dovresti considerare di inserire le implementazioni che hai ora nei metodi in task.
Alpar

@Alpar e altri ; quale scopo è servito per creare qualcosa come a timestamp()o currentWorkingDirectory()metodi come task-s (per esempio). Le funzioni di utilità e cose simili sono nominalmente scalari: non sarebbero attività tranne che ci sono limitazioni sul riutilizzo del codice integrate con Gradle e la maggior parte dei sistemi di compilazione. Mi piace il mondo DRY dove posso creare una cosa UNA VOLTA e riutilizzarla. In realtà, si estende l'esempio di @Pieter VDE Io uso anche un " root.gradle" modello per il mio progetto principale - Il file build.gradle di solito definisce alcune specifiche di progetto e poi basta apply ${ROOT}...
lo farà

Se avete bisogno di un modo centralizzato per il lavoro con le proprietà forse questa domanda può aiutare: stackoverflow.com/questions/60251228/...
GarouDan

Risposte:


76

Non è possibile condividere metodi, ma puoi condividere proprietà extra contenenti una chiusura, che si riduce alla stessa cosa. Ad esempio, dichiara ext.foo = { ... }in common-methods.gradle, usa apply from:per applicare lo script e quindi chiama la chiusura con foo().


1
Fa davvero il trucco! Ma ho una domanda su questo: che ne dici dei metodi che restituiscono qualcosa? Fe File foo(String f)diventerà ext.foo = { f -> ... }, posso quindi fare qualcosa come File f = foo(...):?
Pieter VDE

2
Apparentemente, la domanda nel mio commento precedente è possibile. Quindi grazie Peter, per aver risposto a questa domanda!
Pieter VDE

1
@PeterNiederwieser Perché non è possibile? Gradle.org la pensa diversamente: docs.gradle.org/current/userguide/…
IgorGanapolsky

1
@IgorGanapolsky grazie per il link. Mi chiedo come posso utilizzare un valore generato in un file di build separato nel gradle.build - in questo modo sarebbe molto utile :)
kiedysktos

@IgorGanapolsky In che modo il collegamento che hai condiviso dovrebbe aiutare nel contesto della domanda di Peter VDE?
t0r0X

161

Basandosi sulla risposta di Peter , ecco come esporto i miei metodi:

Contenuto di 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
}

Ed è così che utilizzo questi metodi in un altro 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)
}

Ulteriori informazioni sulla conversione dei metodi in chiusure in Groovy.


c'è qualche motivo specifico per utilizzare il nome di chiusura come ext?
Anoop

1
@AnoopSS Aggiungiamo le due chiusure alle proprietà extra di Gradle . Queste proprietà extra sono raggruppate in un oggetto chiamato ext.
Matthias Braun

Possiamo, in qualche modo, lanciare il valore come una nostra classe, che è definita nel file incluso?
GarouDan

Probabilmente è una buona idea pubblicare una domanda separata con un codice di esempio su questo, @GarouDan.
Matthias Braun

7

Usando il dsl di Kotlin funziona in questo modo:

build.gradle.kts :

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

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

external.gradle.kts :

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

1
fantastico, c'è un modo per condividere il tipo Actual? fondamentalmente stai perdendo l'indipendenza dai tipi e l'aiuto dei compilatori ... se potessi condividere la classe che contiene i tuoi metodi allora potresti usare il compilatore.
vach

0

Un altro approccio per Kotlin DSL potrebbe essere:

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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.