Diverses notes sur les tâches Gradle, des bases aux applications.
Gradle
5.0
Java
openjdk 11.0.1
OS
Windows 10
Pour définir une tâche dans Gradle, écrivez:
build.gradle
task foo
La définition de cette tâche foo
est [task (String)](https: // docs) de Project. Vous appelez la méthode .gradle.org / current / dsl / org.gradle.api.Project.html # org.gradle.api.Project: task (java.lang.String)).
La méthode task ()
retourne un objet qui représente la tâche créée, vous pouvez donc obtenir l'objet de la tâche foo
comme suit:
build.gradle
def foo = task foo
println(foo)
println(foo.class)
Résultat d'exécution
> gradle foo
task ':foo'
class org.gradle.api.DefaultTask_Decorated
La tâche réelle de Gradle est un objet de Task, si elle est simplement créée par task ()
Un objet pour DefaultTask est créé.
Action
La tâche contient une liste de Action en interne.
Cette ʻAction a une action spécifique à effectuer sur cette tâche. Ensuite, lorsque la tâche est lancée, ʻAction
est exécutée dans l'ordre à partir du haut de la liste.
ʻAction peut être ajoutée au début ou à la fin de la liste avec les méthodes
doFirst () ,
doLast () de
Task`.
build.gradle
def foo = task foo
foo.doFirst {
println "two"
}
foo.doFirst {
println "one"
}
foo.doLast {
println "three"
}
foo.doLast {
println "four"
}
Résultat d'exécution
> gradle foo
one
two
three
four
doFirst ()
ajoute ʻAction au début de la liste, et
doLast () ʻajoute ʻAction` à la fin.
Dans l'exemple ci-dessus, doFirst ()
est exécuté deux fois.
Dans ce cas, ʻAction, qui produit
"un" ʻexécuté plus tard, sera inséré en haut de la liste, donc il est sorti dans l'ordre de"un" -> "deux"
.
build.gradle
task foo {
println(delegate)
println(delegate.class)
doFirst {
println("FOO!!")
}
}
Résultat d'exécution
> gradle foo
> Configure project :
task ':foo'
class org.gradle.api.DefaultTask_Decorated
> Task :foo
FOO!!
Lors de la définition d'une tâche avec la méthode task ()
, vous pouvez passer une fermeture comme deuxième argument (https://docs.gradle.org/current/dsl/org.gradle.api.Project.html # org.gradle.api.Project: tâche (java.lang.String,% 20groovy.lang.Closure).
Le délégué
de cette fermeture est l'objet de tâche créé.
Par conséquent, les méthodes et propriétés de la tâche créée peuvent être implicitement accessibles dans la fermeture.
L'exécution Gradle est à peu près divisée en trois phases.
Phase | Contenu |
---|---|
Phase d'initialisation (Initialization) |
Déterminez si le projet est unique ou multiple, etc.Project Créez un objet de. |
Phase de configuration (Configuration) |
Exécutez le script de construction etproject Construisez l'objet. |
Phase d'exécution (Execution) |
Exécutez réellement la tâche spécifiée sur la ligne de commande. |
Plus précisément, dans build.gradle
, l'intérieur du jeu ʻAction` pour la tâche est exécuté dans la phase d'exécution, et les autres sont exécutés dans la phase de paramétrage.
build.gradle
println("Phase de réglage 1")
task foo {
println("Phase de réglage 2")
doFirst {
println("Phase d'exécution 1")
}
println("Phase de réglage 3")
doLast {
println("Phase d'exécution 2")
}
}
task bar {
println("Phase de réglage 4")
}
println("Phase de réglage 5")
Résultat d'exécution
> gradle foo
> Configure project :
Phase de réglage 1
Phase de réglage 2
Phase de réglage 3
Phase de réglage 4
Phase de réglage 5
> Task :foo
Phase d'exécution 1
Phase d'exécution 2
La partie qui est exécutée dans la phase de configuration est toujours exécutée quelle que soit la tâche spécifiée. Par conséquent, si vous écrivez par erreur le processus de la tâche dans la pièce à exécuter dans la phase de paramétrage, le processus sera exécuté même si la tâche n'est pas spécifiée, soyez donc prudent.
build.gradle
task foo {
doFirst {
println foo
println project.foo
println tasks.foo
println tasks.getByName("foo")
println tasks["foo"] // getAt()Sucre de syntaxe de méthode
}
}
Résultat d'exécution
task ':foo'
task ':foo'
task ':foo'
task ':foo'
task ':foo'
Si vous définissez une tâche dans un projet, vous ne pouvez faire référence à la tâche que par le nom de la tâche dans le projet.
Ceci est réalisé en ajoutant l'objet de tâche créé aux propriétés de l'objet Project
.
L'objet de tâche créé est enregistré dans TaskContainer de Project
.
Le TaskContainer
peut être référencé à partir de la propriété [tâches] du projet
(https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:tasks). , TaskContainer
vous permet de référencer des tâches en utilisant l'accès aux propriétés et les méthodes getByName ()
, getAt ()
.
Dans de rares cas, il existe des plugins qui ajoutent un objet d'extension avec le même nom que le nom de la tâche.
Par exemple, Eclipse Plugin est nommé ʻeclipseet [Task](https://docs.gradle.org/current/userguide/ eclipse_plugin.html # eclipsetasks) et [Objet d'extension](https://docs.gradle.org/current/userguide/eclipse_plugin.html#sec:eclipse_configuration) sont définis. Dans ce cas, l'objet référencé dans
project.eclipseest l'objet d'extension. Si vous voulez faire référence à une tâche, vous devez passer par
TaskContainer comme
tasks.eclipse`.
Notez que la méthode spécifiée par une chaîne de caractères telle que getByName ()
peut également faire référence aux tâches d'autres projets comme : someSubProject: fooTask
.
build.gradle
task foo {
doFirst {
println("foo")
}
}
task bar {
doFirst {
println("bar")
}
}
foo.dependsOn bar
Résultat d'exécution
> gradle foo
bar
foo
[DependsOn ()] de Task
(https://docs.gradle.org/current/dsl/org.gradle.api.Task.html#org.gradle.api.Task:dependsOn(java.lang.Object [java.lang.Object] ])) Les dépendances de tâches peuvent être définies à l'aide de la méthode.
Ici, la tâche foo
est définie pour dépendre de la tâche bar
.
Cela garantit que la tâche bar
s'exécute en premier chaque fois que vous exécutez la tâche foo
.
L'ordre d'exécution des tâches Gradle est essentiellement contrôlé en utilisant cette définition de dépendance (des méthodes de contrôle autres que les dépendances sont également disponibles).
Gradle examine les tâches dépendantes avant d'exécuter les tâches spécifiées sur la ligne de commande. Ensuite, les tâches sont exécutées dans l'ordre du côté dépendant.
À ce stade, même s'il existe des tâches qui dépendent d'une pluralité de tâches, toutes les tâches sont contrôlées de sorte qu'elles ne sont toujours exécutées qu'une seule fois.
build.gradle
task foo {
doFirst { println("foo") }
}
task bar {
doFirst { println("bar") }
}
task hoge {
doFirst { println("hoge") }
}
foo.dependsOn bar
hoge.dependsOn foo
hoge.dependsOn bar
Résultat d'exécution
> gradle hoge
bar
foo
hoge
La tâche «hoge» dépend à la fois de «foo» et de «bar». Puisque «foo» dépend également de «bar», un diagramme simple des dépendances de tâches est le suivant.
Les dépendances sont représentées graphiquement
hoge -> foo -> bar
| ^
+--------------+
Si vous exécutez simplement toutes les tâches dépendantes, bar
sera exécuté deux fois.
Cependant, comme mentionné ci-dessus, Gradle contrôle que même s'il dépend de plusieurs tâches, il n'est exécuté qu'une seule fois.
Puisque dependOn
est une méthode de Task
, elle peut également être écrite dans le bloc de configuration comme suit.
build.gradle
task foo {
dependsOn "bar"
doFirst {
println("foo")
}
}
task bar {
doFirst {
println("bar")
}
}
Ici, la tâche bar
est spécifiée sous forme de chaîne de caractères.
S'il s'agit d'une référence de propriété au lieu d'une chaîne, vous obtiendrez l'erreur suivante:
build.gradle
task foo {
dependsOn bar //★ Remplacé par la référence de propriété
doFirst {
println("foo")
}
}
task bar {
doFirst {
println("bar")
}
}
Résultat d'exécution
> gradle foo
...
> Could not get unknown property 'bar' for task ':foo' of type org.gradle.api.DefaultTask.
...
BUILD FAILED in 4s
Une erreur se produit car la propriété «bar» est introuvable.
La partie où dependOn bar
est écrite est la partie qui est exécutée dans la" phase de configuration "dans le cycle de vie de construction.
Dans la phase de configuration, les scripts de construction sont exécutés dans l'ordre du haut.
Au moment où "dependOn bar" est exécuté, la "barre des tâches" n'est pas définie car la "barre des tâches" n'a pas encore été exécutée.
Par conséquent, la tâche bar
n'est pas accessible par référence de propriété dans le bloc de configuration de la tâche foo
au-dessus de la définition de la tâche bar
.
Ce problème peut être évité par l'une des méthodes suivantes.
--Comme mentionné ci-dessus, définissez en spécifiant une chaîne de caractères
--Amenez la définition de tâche bar
au-dessus de la définition de tâche foo
Si cela dépend de l'ordre de la description, il devient vulnérable au changement, donc je pense personnellement qu'il vaut mieux spécifier une chaîne de caractères.
build.gradle
task foo(dependsOn: "bar") {
doFirst {
println("foo")
}
}
task bar {
doFirst {
println("bar")
}
}
Recevoir Map
[task ()](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:task (java.util.Map) ,% 20java.lang.String,% 20groovy.lang.Closure))) Vous pouvez également spécifier la tâche dépendante avec l'argument Map
.
build.gradle
apply plugin: "java"
clean.doFirst { println "clean" }
build.doFirst { println "build" }
task cleanBuild(dependsOn: [clean, build])
Résultat d'exécution
> gradle cleanBuild
build
clean
[clean, build]
est spécifié comme tâche dépendante de la tâche cleanBuild
.
Cependant, lorsque la tâche cleanBuild
est exécutée, les tâches sont exécutées dans l'ordre de build
-> clean
.
De cette façon, la simple spécification de «dependOn» ne détermine pas l'ordre d'exécution des tâches (ordre des noms?).
Comment puis-je le contrôler pour qu'il s'exécute dans l'ordre clean
-> build
?
La première idée simple est de définir dependOn
pour que build
dépende de clean
.
build.gradle
apply plugin: "java"
clean.doFirst { println "clean" }
build.doFirst { println "build" }
build.dependsOn clean
task cleanBuild(dependsOn: [clean, build])
Résultat d'exécution
> gradle cleanBuild
clean
build
Maintenant, les tâches sont exécutées dans l'ordre clean
-> build
.
Cependant, cette méthode rend impossible d'exécuter uniquement «build» (il est toujours «propre»).
Spécifiez uniquement la construction et l'exécution
> gradle build
clean
build
Si possible, je ne veux pas exécuter clean
lors de l'exécution de build
seul.
Si vous souhaitez limiter l'ordre lorsqu'il est spécifié en même temps, mais que vous voulez pouvoir l'exécuter indépendamment, [mustRunAfter (Object ...)](https://docs.gradle.org/current/ Utilisez dsl / org.gradle.api.Task.html # org.gradle.api.Task: mustRunAfter (java.lang.Object [])).
build.gradle
apply plugin: "java"
clean.doFirst { println "clean" }
build.doFirst { println "build" }
build.mustRunAfter clean
task cleanBuild(dependsOn: [clean, build])
Résultat d'exécution
> gradle cleanBuild
clean
build
> gradle build
build
En utilisant taskA.mustRunAfter (taskB)
, vous pouvez forcer l'ordre lorsque taskA
et taskB
sont exécutés en même temps pour être taskB
-> taskA
.
build.gradle
task foo {
doFirst { println "foo" }
finalizedBy "finalizer"
}
task bar {
doFirst {
println "bar"
throw new Exception("test")
}
finalizedBy "finalizer"
}
task finalizer {
doFirst { println "finalizer" }
}
Résultat d'exécution
> gradle foo
foo
finalizer
> gradle bar
bar
finalizer
...
Execution failed for task ':bar'.
> java.lang.Exception: test
...
BUILD FAILED in 3s
[finalizedBy ()](https://docs.gradle.org/current/dsl/org.gradle.api.Task.html#org.gradle.api.Task:finalizedBy(java.lang.Object [])) La tâche définie est toujours exécutée, que la tâche se termine normalement ou anormalement.
Spécifiez quand un processus doit être exécuté, comme la libération de ressources.
build.gradle
task foo {
doFirst { println "foo" }
onlyIf { project.hasProperty("hoge") }
}
Résultat d'exécution
> gradle foo
[Aucune sortie]
> gradle foo -Phoge
foo
Utilisation de onlyIf () , Vous pouvez spécifier les conditions pour exécuter l'action de la tâche.
L'action de la tâche n'est exécutée que lorsque la fermeture passée en argument renvoie «true». Si la fermeture renvoie «false», l'action de la tâche est ignorée.
Cependant, seule cette tâche est ignorée et les tâches et tâches dépendantes spécifiées par finalizedBy
sont exécutées.
build.gradle
task foo {
doFirst { println "foo" }
onlyIf { project.hasProperty("hoge") }
dependsOn "bar"
finalizedBy "finalizer"
}
task bar {
doFirst { println "bar" }
}
task finalizer {
doFirst { println "finalizer" }
}
Résultat d'exécution
> gradle foo
bar
finalizer
L'exécution de «foo» est ignorée, mais la tâche «barre» dépendante et la tâche «finaliseur» spécifiées dans le finaliseur sont en cours d'exécution.
Gradle fournit une API flexible pour sélectionner des fichiers et des répertoires dans la classe Project
.
Lors de l'écriture des paramètres de tâche et des actions, cette API peut être utilisée pour rendre les opérations sur les fichiers concises.
build.gradle
import java.nio.file.Path
task foo {
doFirst {
File file1 = file("foo.txt")
println(file1)
File file2 = file(new File("foo.txt"))
println(file2)
File file3 = file(Path.of("foo.txt"))
println(file3)
}
}
Résultat d'exécution
> gradle foo
F:\etc\...\foo.txt
F:\etc\...\foo.txt
F:\etc\...\foo.txt
La méthode file ()
analyse la valeur reçue en argument et renvoie un objet File
.
Il prend en charge une variété d'entrées allant des chemins de chaîne à File
et Path
(voir la documentation de l'API pour plus de détails).
Si vous voulez que Gradle convertisse correctement n'importe quelle entrée en un objet File
, cette méthode file ()
fonctionne plutôt bien.
build.gradle
task foo {
doFirst {
FileCollection files = files("foo.txt", "bar.txt")
files.each { println it }
}
}
Résultat d'exécution
> gradle foo
F:\etc\...\foo.txt
F:\etc\...\bar.txt
La méthode files ()
remplace FileCollection, qui est une collection de plusieurs fichiers. Produire.
L'argument est un argument de longueur variable, et la valeur qui peut être spécifiée avec file ()
peut être spécifiée de la même manière.
En plus de cela, vous pouvez également transmettre ʻIterable,
Collection`, etc.
Quoi qu'il en soit, il analyse également la plupart des valeurs dans un FileCollection
.
Les méthodes suivantes sont fournies dans FileCollection
.
build.gradle
FileCollection files = files("foo.txt", "bar.txt")
println "asPath = ${files.asPath}"
Résultat d'exécution
asPath = F:\etc\...\foo.txt;F:\etc\...\bar.txt
Obtenez une chaîne qui concatène chaque chemin avec un délimiteur pour chaque plate-forme. Le délimiteur est, par exemple, «:» sous Linux et «;» sous Windows.
Il peut être utilisé avec des options telles que le chemin de classe et le chemin du module qui spécifient plusieurs fichiers.
build.gradle
FileCollection files = files("foo.txt", "bar.txt", "fizz.txt", "buzz.txt")
FileCollection filtered = files.filter { it.name.startsWith("b") }
filtered.each { println it }
Résultat d'exécution
F:\etc\...\bar.txt
F:\etc\...\buzz.txt
La fermeture passée à filter ()
retourne un FileCollection
avec les éléments réduits uniquement auFichier
qui a renvoyé un vrai
.
build.gradle
task foo {
doFirst {
FileTree tree = fileTree("fromDir")
tree.each { println it }
}
}
Résultat d'exécution
> gradle foo
F:\etc\...\fromDir\hoge.txt
F:\etc\...\fromDir\hoge.xml
F:\etc\...\fromDir\sub\foo.txt
F:\etc\...\fromDir\sub\foo.xml
La méthode fileTree ()
est utilisée pour conserver récursivement des fichiers dans le répertoire spécifié [FileTree](https://docs.gradle.org/current/javadoc/org/gradle/api/file/FileTree. html) peuvent être obtenus.
Puisque FileTree
hérite de FileCollection
, il peut être utilisé de la même manière que FileCollection
.
build.gradle
task foo {
doFirst {
FileTree tree = fileTree("fromDir") {
include "**/*.xml"
}
tree.each { println it }
}
}
Résultat d'exécution
> gradle foo
F:\etc\...\fromDir\hoge.xml
F:\etc\...\fromDir\sub\foo.xml
fileTree ()
peut passer une fermeture comme deuxième argument.
Le «délégué» de fermeture est un objet ConfigurableFileTree dans le répertoire spécifié par le premier argument. ..
Comme son nom l'indique, ConfigurableFileTree
est un FileTree
configurable qui vous permet de restreindre des fichiers tels que ʻinclude ()et ʻexclude ()
.
Le modèle de rétrécissement peut être spécifié au format Ant [^ 2].
[^ 2]: Pour le format Ant, recherchez "format de motif fourmi" et vous trouverez diverses informations, alors reportez-vous à cela.
build.gradle
task foo {
doFirst {
FileTree tree = fileTree(dir: "fromDir", include: "**/*.xml")
tree.each { println it }
}
}
Résultat d'exécution
> gradle foo
F:\etc\...\fromDir\hoge.xml
F:\etc\...\fromDir\sub\foo.xml
Dans fileTree ()
qui reçoit Map
comme argument, la valeur à définir dans la propriété de ConfigurableFileTree
peut être spécifiée par Map
.
Vérifiez à nouveau la relation des classes autour de l'opération de fichier.
FileCollection
est une collection de File
.
FileTree
est une collection qui contient récursivement File
dans un répertoire spécifique.
Il y a ConfigurableFileCollection
et ConfigurableFileTree
qui héritent de chacun d'eux, et il est possible de définir pour affiner la cible File
.
build.gradle
task foo {
doFirst {
println "foo"
file("foo.txt").text = project.hoge
}
}
La tâche foo
est une tâche qui renvoie la valeur définie dans la propriété hoge
de project
à foo.txt
.
Essayez d'exécuter cette tâche plusieurs fois.
Résultat d'exécution
> gradle foo -Phoge=HOGE
> Task :foo
foo
BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed
> gradle foo -Phoge=HOGE
> Task :foo
foo
BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed
Bien entendu, lorsque la tâche est exécutée, l'action de la tâche est exécutée et le fichier est sorti.
Cependant, tant que l'entrée n'a pas changé, cette tâche ne sortira que le même résultat, quel que soit le nombre de fois qu'elle est exécutée. Il est inutile de l'exécuter à chaque fois, même si vous savez que la sortie ne change pas.
Si cette tâche prend du temps, elle peut avoir un impact significatif sur le temps de construction.
Gradle fournit un mécanisme pour ignorer l'exécution d'une tâche si le résultat de la tâche ne change pas. Pour utiliser ce mécanisme, il est nécessaire de définir l'entrée / sortie de la tâche.
build.gradle
task foo {
def outputFile = file("foo.txt")
inputs.property "hoge", project.hoge
outputs.file outputFile
doFirst {
println "foo"
outputFile.text = hoge
}
}
Résultat d'exécution
> gradle foo -Phoge=HOGE
> Task :foo
foo
BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed
> gradle foo -Phoge=HOGE
> Task :foo UP-TO-DATE
BUILD SUCCESSFUL in 3s
1 actionable task: 1 up-to-date
> gradle foo -Phoge=HOGEHOGE
> Task :foo
foo
BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed
Lorsque la valeur de hoge
est définie sur la même valeur que la première fois et qu'elle est exécutée, ʻUP-TO-DATE (le plus récent) est affiché à droite de l'affichage de la tâche
foo, et l'exécution de la tâche est sautée. Après avoir changé la valeur de
hoge, la tâche
foo` a été exécutée à nouveau.
build.gradle
task foo {
...
inputs.property "hoge", project.hoge
outputs.file outputFile
...
}
Pour définir l'entrée et la sortie d'une tâche, accédez d'abord à l'objet pour définir l'entrée et la sortie à l'aide des deux propriétés suivantes définies dans Tâche
.
Les propriétés respectives sont TaskInputs (https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/TaskInputs.html) et TaskOutputs (https://docs.gradle.org/). current / javadoc / org / gradle / api / tasks / TaskOutputs.html) est renvoyé. Utilisez les méthodes fournies par ces classes pour définir des entrées et des sorties spécifiques.
Gradle enregistre le contenu de l'entrée et de la sortie lorsque la tâche est exécutée. Ensuite, la prochaine fois que la même tâche est exécutée, il vérifie si le contenu de l'entrée et de la sortie a changé [^ 1]. Si les entrées et les sorties n'ont pas changé, Gradle ignore l'exécution de la tâche. Si l'une des valeurs spécifiées pour l'entrée et la sortie a changé, la tâche sera exécutée normalement.
[^ 1]: Si le fichier de sortie est supprimé, il doit être réexécuté, il est donc nécessaire de vérifier également l'état de la sortie.
Les entrées et les sorties doivent être définies. Ce mécanisme de saut ne fonctionne pas si un seul (entrée uniquement, sortie uniquement) est spécifié.
Les trois suivants peuvent être largement utilisés pour l'entrée.
--Propriétés - property(String, Object) - properties(Map)
La propriété peut être n'importe quelle clé et valeur, comme indiqué dans l'exemple ci-dessus. Cependant, les valeurs doivent être sérialisables et comparables à ʻequals () `.
Si vous spécifiez un fichier, il est vérifié pour voir si le contenu du fichier a changé.
Si un répertoire est spécifié, l'état sous ce répertoire est vérifié. Si un fichier ou un répertoire est créé dans le répertoire ou si le contenu du fichier est modifié, il est jugé que l'entrée a changé. Ce jugement cible récursivement les sous-répertoires et les inférieurs.
build.gradle
task foo {
...
inputs.file file("input.txt") //Spécifiez le fichier d'entrée
inputs.dir file("inputDir") //Spécification du répertoire d'entrée
...
}
Les deux sorties suivantes peuvent être utilisées.
build.gradle
task foo {
...
outputs.file file("output.txt") //Spécifiez le fichier de sortie
outputs.dir file("outputDir") //Spécification du répertoire de sortie
...
}
build.gradle
tasks.addRule("Pattern: echo<MESSAGE>") { taskName ->
if (taskName.startsWith("echo")) {
task(taskName) {
doFirst { println(taskName - "echo") }
}
}
}
Résultat d'exécution
> gradle echoHoge
Hoge
> gradle tasks
...
Rules
-----
Pattern: echo<MESSAGE>
Méthode addRule () de TaskContainer
Vous pouvez utiliser pour définir ce que l'on appelle une règle de tâche.
ʻAddRule () `transmet la description de la règle de tâche dans le premier argument et la fermeture dans le deuxième argument. La fermeture reçoit le nom de la tâche à laquelle elle essayait de faire référence (ici, la chaîne «" echoHoge "» spécifiée sur la ligne de commande est passée).
Si vous définissez une tâche avec le nom reçu dans cette fermeture, aucune erreur ne se produira même si la tâche avec ce nom n'est pas prédéfinie et la tâche définie dynamiquement sera adoptée. En d'autres termes, même pour les tâches pour lesquelles le nom de la tâche ne peut pas être défini statiquement à l'avance, la tâche peut être définie dynamiquement au moment de l'exécution en fournissant un modèle (règle) dans le nom de la tâche.
Les règles définies dans cette règle de tâche peuvent également être référencées par dependOn
.
build.gradle
tasks.addRule("Pattern: echo<MESSAGE>") { taskName ->
if (taskName.startsWith("echo")) {
task(taskName) {
doFirst { println(taskName - "echo") }
}
}
}
task foo(dependsOn: echoBar) {
doFirst { println "foo" }
}
Résultat d'exécution
> gradle foo
Bar
foo
Ici, ʻechoBarest spécifié dans
dependOn de la tâche
foo. Encore une fois, les règles de tâche s'appliquent et la tâche ʻechoBar
est générée dynamiquement.
build.gradle
apply plugin: "base"
Résultat d'exécution
> gradle tasks
...
Rules
-----
Pattern: clean<TaskName>: Cleans the output files of a task.
Lorsque vous chargez le plug-in base
, la règle clean
sera appliquée.
(Ce plug-in est chargé ensemble si vous appliquez le plug-in Java, etc., donc fondamentalement, il n'est pas chargé explicitement)
Cette règle crée une tâche qui supprime le fichier de sortie de n'importe quelle tâche.
build.gradle
apply plugin: "base"
task foo {
def outputFile = file("foo.txt")
outputs.file outputFile
doFirst {
outputFile.text = "foo!!"
}
}
Ici, nous définissons une tâche appelée «foo».
Cette tâche définit un fichier appelé foo.txt
comme fichier de sortie.
Résultat d'exécution
> type foo.txt
Le fichier spécifié est introuvable.
> gradle foo
...
BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed
> type foo.txt
foo!!
> gradle cleanFoo
...
BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed
> type foo.txt
Le fichier spécifié est introuvable.
La tâche cleanFoo
est générée dynamiquement par la règle clean
et est définie pour supprimer le fichier de sortie de la tâche foo
.
Les tâches créées par task ()
ne peuvent être utilisées que dans ce projet.
En outre, le même processus ne peut pas être réutilisé dans plusieurs emplacements avec des paramètres différents.
Si vous souhaitez réutiliser la même tâche dans plusieurs projets avec des paramètres différents, créez une tâche personnalisée.
build.gradle
class FooTask extends DefaultTask {
@TaskAction
def foo() {
println("FOO!!")
}
}
task foo(type: FooTask)
Résultat d'exécution
> gradle foo
FOO!!
Les tâches personnalisées sont créées en héritant de «DefaultTask». Si vous définissez une méthode arbitraire et que vous l'annotez avec @TaskAction, cette méthode sera l'action de la tâche. Sera exécuté.
Pour utiliser la tâche personnalisée que vous avez créée, recevez Map
[task ()](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api Utilisez .Project: task (java.util.Map,% 20java.lang.String)).
Dans cet argument Map
, spécifiez le type de tâche que vous souhaitez créer dans type
.
Ensuite, l'objet de tâche sera créé avec le type spécifié.
Ici, par souci de simplicité, les tâches personnalisées sont définies dans le même script de construction. Cependant, en réalité, il sera défini dans un emplacement externe qui peut être référencé par plusieurs projets (comme «buildSrc» décrit plus tard ou un fichier jar externe).
build.gradle
class FooTask extends DefaultTask {
String message
@TaskAction
def foo() {
println("FOO!! message=${message}")
}
}
task foo(type: FooTask) {
message = "Hello World"
}
Résultat d'exécution
> gradle foo
FOO!! message=Hello World
Une tâche créée en spécifiant un type avec «type» est un objet de ce type. En d'autres termes, si vous définissez des propriétés et des méthodes de paramétrage pour une tâche personnalisée, vous pouvez spécifier les paramètres de l'objet de tâche partout où vous pouvez accéder à l'objet de tâche généré.
Ici, la valeur est définie dans la propriété message
dans le bloc de paramètres.
build.gradle
class FooTask extends DefaultTask {
List inputFiles = []
Object output
@TaskAction
def foo() {
def out = project.file(this.output)
out.text = ""
project.files(this.inputFiles)
.each { out.append("${it.name}\n") }
}
}
task foo (type: FooTask) {
inputFiles = ["fromDir/hoge.txt", "build.gradle", file(".gitignore")]
output = file("output/test.txt")
}
Lors de la définition de fichiers et de répertoires pour l'entrée et la sortie des tâches, le type doit être un type qui peut contenir tout ce qui peut être "Objet" ou "Liste".
Ensuite, lorsque vous utilisez réellement la valeur de réglage, convertissez en utilisant file ()
ou files ()
de Project
.
Cela vous permet de spécifier des fichiers dans une variété de formats pris en charge par Project # file ()
, tels que des chaînes et des objets File
, vous donnant une plus grande flexibilité de configuration.
build.gradle
class FooTask extends DefaultTask {
@Input
String message
@OutputFile
Object output
@TaskAction
def foo() {
project.file(output).text = message
}
}
task foo(type: FooTask) {
message = "Hello World!!"
output = "foo.txt"
}
Résultat d'exécution
> gradle foo
...
BUILD SUCCESSFUL in 4s
1 actionable task: 1 executed
> type foo.txt
Hello World!!
> gradle foo
...
BUILD SUCCESSFUL in 4s
1 actionable task: 1 up-to-date
Les tâches personnalisées permettent de définir les entrées et sorties de tâches avec des annotations.
Vous pouvez définir les entrées et sorties de tâche en annotant les champs de tâche personnalisés et la méthode Getter avec les annotations suivantes.
--Contribution - @Input - @InputFile - @InputFiles - @InputDirectory --Production - @OutputFile - @OutputFiles - @OutputDirectory - @OutputDirectories
Les classes de tâches sont fournies en standard pour les processus susceptibles d'être utilisés fréquemment. Par exemple, il y a les tâches suivantes.
Copy
build.gradle
task foo(type: Copy) {
from "fromDir"
into "toDir"
}
Résultat d'exécution
> tree /f fromDir
...
│ hoge.txt
│
└─sub
foo.txt
> gradle foo
...
> tree /f toDir
│ hoge.txt
│
└─sub
foo.txt
Copie La tâche effectue une copie d'un fichier ou d'un répertoire.
CopySpec implémenté par Copy
fournit le paramétrage de la méthode de copie. Utilisez l'API existante.
CopySpec
fournit diverses méthodes pour réduire la cible de la copie et spécifier la destination de la copie, et il permet des paramètres assez flexibles.
build.gradle
task foo(type: Copy) {
from "fooDir", "barFile"
from file("fizzDir"), file("buzzFile")
...
}
Spécifiez le fichier ou le répertoire source de la copie.
Vous pouvez spécifier plusieurs arguments, ou vous pouvez appeler from ()
lui-même plusieurs fois.
La valeur passée en argument est finalement les [files (Object ...)] de Project
(https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle .api.Project: passé à la méthode files (java.lang.Object [])).
Par conséquent, vous pouvez transmettre diverses valeurs telles qu'un chemin de chaîne ou un objet File
.
build.gradle
task foo(type: Copy) {
from("fromDir") {
include "**/*.txt"
}
...
}
Vous pouvez passer une fermeture comme deuxième argument de from ()
.
Le délégué
de cette fermeture est CopySpec
, et il est possible de restreindre davantage les conditions de copie uniquement dans le répertoire spécifié parfrom ()
.
Ici, les fichiers à copier par ʻinclude () sont limités à
* .txt`.
build.gradle
task foo(type: Copy) {
into "toDir"
...
}
Spécifiez le répertoire de destination de la copie.
build.gradle
task foo(type: Copy) {
include "*.txt", "**/*.xml"
...
}
Vous pouvez spécifier les conditions à inclure dans la cible de copie en spécifiant le modèle au format Ant.
build.gradle
task foo(type: Copy) {
exclude "**/*.class", "**/*.bk"
...
}
Ici, vous pouvez également spécifier les conditions à exclure de la copie avec un modèle au format Ant.
build.gradle
task foo(type: Copy) {
from "fromDir"
into "toDir"
rename { name ->
name.toUpperCase()
}
}
Vous pouvez utiliser rename ()
pour renommer le fichier lors de la copie.
Dans le cas de rename ()
qui reçoit une fermeture, le nom du fichier avant la copie (String
) est passé à l'argument de la fermeture.
Ensuite, la valeur renvoyée par la fermeture est utilisée comme nom de fichier après la copie.
Dans le cas de l'implémentation ci-dessus, le nom de fichier dans lequel le nom de fichier d'origine est entièrement en majuscule est utilisé comme nom de fichier de destination de la copie.
build.gradle
task foo(type: Copy) {
from "fromDir"
into "toDir"
rename(/(.*)\.([a-z]+)/, '$1_copy.$2')
}
Rename ()
, qui reçoit deux String
s comme arguments, passe une expression régulière comme premier argument et l'expression renommée comme deuxième argument.
La partie définie comme un groupe dans l'expression régulière du premier argument (la partie entourée par «()») peut être désignée par «$ n» dans l'expression du deuxième argument («n» est un numéro de série de 1).
Dans l'exemple ci-dessus, le premier groupe est (. *)
, Qui pointe vers le nom de base du fichier avant l'extension.
Le deuxième groupe est la partie ([a-z] +)
, qui pointe vers la partie d'extension.
Ensuite, en spécifiant «$ 1_copy. $ 2» dans l'expression après avoir renommé, le fichier est renommé avec «_copy» à la fin du nom de base et copié.
Lorsqu'il est réellement déplacé, il devient comme suit.
Résultat d'exécution
> tree /f fromDir
...
│ hoge.txt
│ hoge.xml
│
└─sub
foo.txt
foo.xml
> gradle foo
...
> tree /f toDir
...
│ hoge_copy.txt
│ hoge_copy.xml
│
└─sub
foo_copy.txt
foo_copy.xml
Pour la classe Project
, copy (Closure) est fournie.
L'argument de fermeture delegate
implémente l'interface CopySpec
, qui vous permet de spécifier la cible de copie de la même manière que la tâche Copy
.
build.gradle
task foo {
doFirst {
copy {
from "fromDir"
into "toDir"
include "**/*.txt"
}
}
}
Si vous souhaitez effectuer plusieurs opérations de copie en une seule tâche, vous pouvez également utiliser la méthode copy ()
de ce Projet
.
Delete
build.gradle
task foo(type: Delete) {
delete "targetDir/aaa.txt", "targetDir/hoge"
}
Résultat d'exécution
> tree /f targetDir
│ aaa.txt
│ bbb.txt
│
└─hoge
│ ccc.txt
│
└─fuga
ddd.txt
> gradle foo
...
BUILD SUCCESSFUL in 5s
> tree /f targetDir
bbb.txt
Supprimer Les tâches vous permettent de supprimer des fichiers et des dossiers.
La classe Delete
implémente l'interface DeleteSpec.
[Supprimer (Objet ...)] défini dans cette interface (https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Delete.html#org.gradle.api.tasks .Delete: delete (java.lang.Object [])) Spécifiez la cible de suppression avec la méthode.
La valeur spécifiée dans l'argument est transmise à la méthode Project # files (Object ...)
, elle peut donc être spécifiée dans différents types tels qu'une chaîne de caractères et File
.
«Delete» lui-même ne fournit pas d'API qui vous permet de spécifier «un fichier dans un répertoire spécifique et un modèle spécifique».
Cependant, comme mentionné ci-dessus, la valeur passée à delete ()
est transmise à Project # files ()
, vous pouvez donc également passer FileCollection
.
En d'autres termes, il peut être spécifié comme suit.
build.gradle
task foo(type: Delete) {
delete fileTree(dir: "targetDir", include: "hoge/**/*.txt")
}
Résultat d'exécution
> tree /f targetDir
│ aaa.txt
│ bbb.txt
│
└─hoge
│ ccc.txt
│
└─fuga
ddd.txt
> gradle foo
...
BUILD SUCCESSFUL in 5s
> tree /f targetDir
│ aaa.txt
│ bbb.txt
│
└─hoge
└─fuga
Comme copy ()
, delete (Action) est fournie dans Project
.
Puisque la fermeture delegate
implémente DeleteSpec
, vous pouvez spécifier la cible de suppression de la même manière que la tâche Delete
.
build.gradle
task foo {
doFirst {
project.delete { delete "targetDir" }
}
}
La mise en garde ici est que chaque fois que vous appelez la méthode delete ()
, vous devez la préfixer avec project
, comme project.delete ()
.
build.gradle
task foo {
doFirst {
project.delete {
println "project.delete.delegate=${delegate.class}"
}
delete {
println "delete.delegate=${delegate.class}"
}
}
}
Résultat d'exécution
> gradle foo
project.delete.delegate=class org.gradle.api.internal.file.delete.DefaultDeleteSpec
delete.delegate=class build_32bm3o8iprxruz9mv43mbtt86$_run_closure1$_closure2
Pour project.delete ()
, delegate
est DeleteSpec
, mais pourdelete ()
seulement, ce n'est pas DeleteSpec
.
Au fait, pour copy ()
, il n'y a pas de problème car delegate
devient CopySpec
même si project
n'est pas ajouté.
Apparemment, si vous avez seulement une méthode qui prend ʻAction comme argument, vous aurez besoin de
project (
copy ()a
copy (Closure)et
copy (Action), mais
delete ( ) ʻOnlydelete (Action)
).
Pour être honnête, je ne sais pas pourquoi cela se produit.
Sync
build.gradle
task foo(type: Sync) {
from "fromDir"
into "toDir"
include "**/*.txt"
}
Résultat d'exécution
> tree /f fromDir
│ aaa.txt
│ bbb.txt
│ eee.xml
│
└─hoge
│ ccc.txt
│ fff.xml
│
└─fuga
ddd.txt
ggg.xml
> tree /f toDir
hoge.txt
> gradle foo
...
BUILD SUCCESSFUL in 5s
> tree /f toDir
│ aaa.txt
│ bbb.txt
│
└─hoge
│ ccc.txt
│
└─fuga
ddd.txt
Sync La tâche est la même que le répertoire spécifié par ʻintoet le répertoire spécifié par
from`. Mettre à jour à l'état.
Puisque «Sync» implémente «CopySpec», vous pouvez contrôler la méthode de copie de la même manière que la tâche «Copier».
Le fichier hoge.txt
qui existait dans toDir
avant l'exécution de la tâche a été supprimé.
La synchronisation avec Sync
est effectuée ** par défaut après la suppression de tous les fichiers et dossiers de destination **.
Si vous avez un fichier ou un dossier qui n'existe que dans la destination de synchronisation et que vous ne voulez pas qu'il soit supprimé, [préserve](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Sync.html Spécifiez # org.gradle.api.tasks.Sync: preserve (org.gradle.api.Action)).
build.gradle
task foo(type: Sync) {
from "fromDir"
into "toDir"
include "**/*.txt"
preserve {
include "hoge.txt"
}
}
Résultat d'exécution
> tree /f toDir
fuga.txt
hoge.txt
piyo.txt
> gradle foo
...
BUILD SUCCESSFUL in 5s
> tree /f toDir
│ aaa.txt
│ bbb.txt
│ hoge.txt
│
└─hoge
│ ccc.txt
│
└─fuga
ddd.txt
La cible spécifiée par ʻinclude dans
preserve n'est plus supprimée (
preserve` signifie" save ").
Il est également possible de spécifier ʻexclude, et si ʻexclude "hoge.txt"
est spécifié, seul hoge.txt
sera supprimé (il ne sera pas enregistré).
Si ʻinclude et ʻexclude
sont spécifiés en même temps, le réglage de ʻinclude` semble avoir la priorité.
Comme vous pouvez l'imaginer, [sync (Action)](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:sync(org.gradle.api. Action)) La méthode est également fournie dans Projet
.
Cependant, le délégué
de cette fermeture implémente l'interface CopySpec
.
En d'autres termes, conserve
ne peut pas être spécifié (la référence dit que conserve
peut être spécifié, mais si vous l'écrivez réellement, une erreur se produira).
build.gradle
task foo {
doFirst {
project.sync {
from "fromDir"
into "toDir"
include "**/*.txt"
}
}
}
Puisque sync ()
n'a que sync (Action)
, une erreur se produira à moins que le projet
ne soit modifié comme delete ()
.
Exec
build.gradle
task foo(type: Exec) {
workingDir "workDir"
environment MESSAGE: "Hello World!!"
commandLine "cmd", "/c", "echo", "%MESSAGE%", ">", "hello.txt"
}
Résultat d'exécution
> gradle foo
...
BUILD SUCCESSFUL in 5s
> type workDir\hello.txt
Hello World!!
Exec Les tâches vous permettent d'exécuter des commandes arbitraires. ʻExec` implémente l'interface ExecSpec, qui définit les méthodes de configuration. ..
[commandLine (Object ...)](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Exec.html#org.gradle.api.tasks.Exec:commandLine (java.) Dans lang.Object [])), spécifiez la commande que vous souhaitez exécuter.
Pour Linux, vous pouvez commencer avec la commande que vous voulez exécuter directement, mais pour Windows, vous devez continuer avec cmd / c <commande que vous voulez réellement exécuter>
.
[workingDir (Object)](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Exec.html#org.gradle.api.tasks.Exec:workingDir(java.lang.Object) Vous pouvez spécifier le répertoire de travail lors de l'exécution avec)).
environnement (carte)), Vous pouvez définir des variables d'environnement dans le sous-processus qui exécute la commande.
build.gradle
task foo {
doFirst {
exec {
commandLine "cmd", "/c", "echo", "Hello World!!"
}
}
}
Projet
exec (fermeture)) Vous pouvez utiliser la méthode pour exécuter des commandes de la même manière que ʻExec`.
Le délégué
de fermeture est ʻExecSpec`.
Zip
build.gradle
task foo(type: Zip) {
baseName = "foo"
from "fromDir"
destinationDir = file("toDir")
include "**/*.txt"
}
Résultat d'exécution
> tree /f fromDir
│ aaa.txt
│ bbb.txt
│ eee.xml
│
└─hoge
│ ccc.txt
│ fff.xml
│
└─fuga
ddd.txt
ggg.xml
> gradle foo
...
BUILD SUCCESSFUL in 5s
> dir /b toDir
foo.zip
La tâche Zip vous permet de compresser n'importe quel répertoire.
Zip
implémente l'interface CopySpec
, donc il peut être ciblé de la même manière que la tâche Copy
.
Cependant, la destination de sortie est destinationDir Précisez dans la propriété.
Notez que cette propriété est File
, pas ʻObject. Si vous avez appliqué le plug-in
base,
destinationDirest par défaut
build / distributions. Si le plug-in
base n'est pas appliqué (fondamentalement impossible ...), la spécification de
destinationDir` est obligatoire.
Le nom du fichier zip est créé en concaténant les valeurs définies dans certaines propriétés.
build.gradle
task foo(type: Zip) {
baseName = "baseName"
appendix = "appendix"
version = "version"
classifier = "classifier"
extension = "extension"
from "fromDir"
destinationDir = file("toDir")
include "**/*.txt"
}
Résultat d'exécution
> gradle foo
...
BUILD SUCCESSFUL in 5s
> dir /b toDir
baseName-appendix-version-classifier.extension
Le nom de fichier entier est créé en connectant chaque propriété avec un trait d'union comme suit.
(Les propriétés qui ne sont pas définies sont ignorées (si ʻextension n'est pas définie, elle devient
"zip" `))
baseName-appendix-version-classifier.extension
Si vous souhaitez spécifier le nom complet du fichier à la fois, [archiveName](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Zip.html#org.gradle.api.tasks .bundling.Zip: archiveName) Spécifiez la propriété.
Le chemin du fichier zip généré par la tâche Zip
est [archivePath](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Zip.html#org.gradle" Vous pouvez le vérifier dans la propriété .api.tasks.bundling.Zip: archivePath).
Malheureusement? Il n'y a pas de méthode appelée zip ()
dans Project
.
[ZipTree (Object)](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.] Pour extraire le contenu de zip, mais pas un substitut. La méthode api.Project: zipTree (java.lang.Object)) est fournie.
Si vous spécifiez le chemin du fichier zip cible comme argument, FileTree
contenant les informations sur le contenu de ce zip est renvoyé.
build.gradle
task foo {
doFirst {
def zip = zipTree("toDir/foo.zip")
zip.each { println it }
}
}
Résultat d'exécution
> gradle foo
F:\etc\...\build\tmp\expandedArchives\foo.zip_d658f891babbd7031de320615856ccb1\aaa.txt
F:\etc\...\build\tmp\expandedArchives\foo.zip_d658f891babbd7031de320615856ccb1\bbb.txt
F:\etc\...\build\tmp\expandedArchives\foo.zip_d658f891babbd7031de320615856ccb1\eee.xml
F:\etc\...\build\tmp\expandedArchives\foo.zip_d658f891babbd7031de320615856ccb1\hoge\ccc.txt
F:\etc\...\build\tmp\expandedArchives\foo.zip_d658f891babbd7031de320615856ccb1\hoge\fff.xml
F:\etc\...\build\tmp\expandedArchives\foo.zip_d658f891babbd7031de320615856ccb1\hoge\fuga\ddd.txt
F:\etc\...\build\tmp\expandedArchives\foo.zip_d658f891babbd7031de320615856ccb1\hoge\fuga\ggg.xml
Immédiatement après avoir fait zipTree (), le fichier zip n'a pas encore été décompressé.
Lorsque vous essayez d'accéder aux informations du fichier dans ZipTree
, le fichier zip est en fait décompressé dans le répertoire temporaire et vous pouvez accéder aux informations du fichier.
En combinant ces «zipTree ()» et «copy ()», vous pouvez reproduire la décompression de zip.
build.gradle
task foo {
doFirst {
copy {
from zipTree("toDir/foo.zip")
into "build/unzip"
}
}
}
Cela décompressera le contenu du zip sous le répertoire build / unzip
.
buildSrc Gradle a son propre projet de déploiement de classes utilisées dans les scripts de construction.
Structure des dossiers
|-build.gradle
`-buildSrc/
`-src/main/groovy/
`-sample/
`-HogeTask.groovy
Le répertoire racine buildSrc
devient un projet dédié.
Vous pouvez placer votre propre tâche ou code de plug-in dans le répertoire src / main / groovy
de ce projet.
HogeTask.groovy
package sample
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class HogeTask extends DefaultTask {
@TaskAction
def hoge() {
println("Hello Hoge.")
}
}
build.gradle
task foo(type: sample.HogeTask)
Résultat d'exécution
> gradle foo
Hello Hoge.
Si le code source existe dans buildSrc
, il sera automatiquement compilé lors de l'exécution de la tâche et rendu disponible dans le script de construction.
En utilisant une tâche personnalisée, la logique de la tâche peut être définie à l'avance et seule la valeur définie peut être commutée et réutilisée à plusieurs endroits. Cependant, une tâche personnalisée n'est qu'une tâche unique et toutes les générations de tâches et les paramètres détaillés doivent être spécifiés par l'utilisateur.
Afin de partager et de réutiliser un plus large éventail de processus tels que la création de plusieurs tâches et la définition de dépendances entre les tâches, un mécanisme appelé ** plug-in ** est utilisé.
Structure des dossiers
|-build.gradle
`-buildSrc/
`-src/main/groovy/
`-sample/
`-FooPlugin.groovy
FooPlugin.groovy
package sample
import org.gradle.api.Project
import org.gradle.api.Plugin
class FooPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.task("hello") {
doFirst { println("FOO!!") }
}
}
}
build.gradle
apply plugin: sample.FooPlugin
Résultat d'exécution
> gradle hello
FOO!!
Les plugins sont créés en implémentant l'interface Plugin (l'argument de type est Project
). ..
La méthode ʻApply (T) est implémentée et le traitement du plug-in y est décrit. Le contenu à décrire est le même que le contenu normalement décrit dans
build.gradle, et il n'y a aucun problème. Cependant, dans le cas de
build.gradle, la délégation à
Project a été implicitement exécutée, donc
task () etc. pourrait être appelée directement, mais ici la délégation implicite est effectuée. Puisqu'il n'y a rien de tel, il est nécessaire d'appeler explicitement la méthode de
Project`.
Le plug-in créé peut être chargé avec ʻapply` comme les autres plug-ins.
Si vous souhaitez transmettre la valeur du paramètre au plug-in, utilisez le mécanisme de l'objet d'extension.
FooPlugin.groovy
package sample
import org.gradle.api.Project
import org.gradle.api.Plugin
class FooPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
def foo = project.extensions.create("foo", FooPluginExtension)
project.task("hello") {
doFirst { println(foo.message) }
}
}
}
class FooPluginExtension {
String message
}
Pour créer un objet d'extension, utilisez la méthode create ()
de ExtensionContainer.
ʻExtensionContainerest obtenu à partir de la propriété [extensions](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:extensions) de
Project` ça peut.
La méthode create ()
passe le nom de l'objet d'extension dans le premier argument et le type de l'objet d'extension dans le second argument.
Ici, «foo» est spécifié pour le nom et «FooPluginExtension» est spécifié pour le type.
La valeur de retour de create ()
est un objet de la classe spécifiée par le deuxième argument, et la valeur de réglage spécifiée dans le script de construction est accessible via cet objet.
L'objet d'extension généré a été ajouté en tant que propriété à Project
afin qu'il puisse être référencé par le nom spécifié dans create ()
.
build.gradle
apply plugin: sample.FooPlugin
foo.message = "Hello Foo!!"
Résultat d'exécution
> gradle hello
Hello Foo!!
Le bloc de réglage étant disponible pour l'objet d'extension, il peut également être décrit comme suit.
build.gradle
apply plugin: sample.FooPlugin
foo {
message = "Hello Foo!!"
}
Lorsqu'il existe plusieurs valeurs de réglage, la description peut être simplifiée à l'aide du bloc de réglage.
Si vous souhaitez recevoir l'argument dans le constructeur de l'objet d'extension, écrivez comme suit.
FooPlugin.groovy
package sample
import org.gradle.api.Project
import org.gradle.api.Plugin
class FooPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
def foo = project.extensions.create("foo", FooPluginExtension, project)
project.task("hello") {
doFirst { println(foo.outputDir) }
}
}
}
class FooPluginExtension {
Object outputDir
FooPluginExtension(Project project) {
this.outputDir = project.file("${project.buildDir}/foo")
}
}
L'objet d'extension FooPluginExtension
prend un objet Project
et définit la valeur par défaut de ʻoutputDir sur la valeur générée à partir de
Project`.
Pour passer une valeur à cet argument de constructeur, implémentez-le de sorte que la valeur correspondante soit passée après le troisième argument de la méthode create ()
.
Le troisième argument de create ()
est un argument de longueur variable, et la valeur spécifiée ici est passée au constructeur de l'objet d'extension tel quel.
FooPlugin.groovy
package sample
import org.gradle.api.Project
import org.gradle.api.Plugin
class FooPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
def foo = project.extensions.create("foo", FooPluginExtension)
project.task("copyFile") {
inputs.file foo.inputFile
outputs.dir foo.outputDir
doFirst {
project.copy {
from foo.inputFile
into foo.outputDir
}
}
}
}
}
class FooPluginExtension {
Object inputFile
Object outputDir
}
Une tâche appelée copyFile
est créée et implémentée pour copier l'objet d'extension ʻinputFile dans ʻoutputDir
.
De plus, ʻinputFile et ʻoutputDir
sont respectivement définis pour l'entrée et la sortie de la tâche copyFile
.
build.gradle
apply plugin: sample.FooPlugin
foo {
inputFile = "fromDir/aaa.txt"
outputDir = "build"
}
Lorsque je fais cela, la construction échoue comme suit:
Résultat d'exécution
> gradle copyFile
...
> Task :copyFile FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Some problems were found with the configuration of task ':copyFile'.
> No value has been specified for property '$1'.
...
Avec cela seul, je ne sais pas de quoi vous parlez, mais si vous ajoutez la sortie suivante pour le débogage, vous verrez ce qui se passe.
FooPlugin.groovy
package sample
import org.gradle.api.Project
import org.gradle.api.Plugin
class FooPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
println "FooPlugin.apply()début"
def foo = project.extensions.create("foo", FooPluginExtension)
project.task("copyFile") {
inputs.file foo.inputFile
outputs.dir foo.outputDir
println "foo.inputFile=${foo.inputFile}"
println "foo.outputDir=${foo.outputDir}"
doFirst {
project.copy {
from foo.inputFile
into foo.outputDir
}
}
}
println "FooPlugin.apply()Fin"
}
}
class FooPluginExtension {
Object inputFile
Object outputDir
}
build.gradle
println "Avant d'appliquer FooPlugin"
apply plugin: sample.FooPlugin
println "Après avoir appliqué FooPlugin"
println "toto Spécifiez la valeur de paramètre pour l'objet d'extension"
foo {
inputFile = "fromDir/aaa.txt"
outputDir = "build"
}
Résultat d'exécution
> gradle createFile
...
Avant d'appliquer FooPlugin
FooPlugin.apply()début
foo.inputFile=null
foo.outputDir=null
FooPlugin.apply()Fin
Après avoir appliqué FooPlugin
toto Spécifiez la valeur de paramètre pour l'objet d'extension
> Task :copyFile FAILED
...
Au stade de la définition de l'entrée / sortie de la tâche createFile
, la valeur n'a pas encore été définie pour l'objet d'extension foo
.
Par conséquent, la spécification d'entrée / sortie est «nulle».
L'application du plug-in est effectuée dans la phase de paramétrage du cycle de vie de construction, et le processus de paramétrage est essentiellement exécuté dans l'ordre du haut.
Par conséquent, dans la méthode ʻapply () du plug-in personnalisé, l'objet d'extension
foo` n'a pas encore été défini, donc la valeur ne peut pas être référencée.
En bref, il est dans un état étrange car vous essayez de vous référer à la valeur qui sera définie après l'application du plug-in lors de l'application du plug-in. Si toutes les valeurs définies dans l'objet d'extension sont référencées dans la phase d'exécution, un tel problème ne se produit pas.
Cependant, comme les réglages d'entrée / sortie doivent être spécifiés dans la phase de réglage, il sera impossible de régler l'entrée / sortie telle quelle.
Ce problème peut être évité en utilisant Property
.
FooPlugin.groovy
package sample
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.api.provider.Property
class FooPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
def foo = project.extensions.create("foo", FooPluginExtension, project)
project.task("copyFile") {
inputs.file foo.inputFile
outputs.dir foo.outputDir
doFirst {
project.copy {
from foo.inputFile
into foo.outputDir
}
}
}
}
}
class FooPluginExtension {
Property<Object> inputFile
Property<Object> outputDir
FooPluginExtension(Project project) {
this.inputFile = project.objects.property(Object)
this.outputDir = project.objects.property(Object)
}
}
build.gradle
apply plugin: sample.FooPlugin
foo {
inputFile = "fromDir/aaa.txt"
outputDir = "build"
}
Résultat d'exécution
> gradle copyFile
...
BUILD SUCCESSFUL in 6s
ʻInputFile, ʻoutputDir
utilise le type Property comme type de propriété.
Une instance de Property
peut être créée avec la méthode property (Class)
de ObjectFactory.
ʻObjectFactory peut être obtenu à partir de la méthode
getObjects () de
Project`.
File ()
etc. de Project
prend en charge ce type Property
, donc il peut être passé tel quel, mais si vous avez besoin de la valeur du contenu, vous pouvez l'obtenir en utilisant la méthodeget ()
.
Vous pouvez également changer la valeur avec la méthode set ()
.
Par ailleurs, dans l'exemple ci-dessus, une chaîne de caractères (type String
) est définie par l'opérateur d'affectation pour une propriété qui doit être de type Property
.
Normalement, une telle description entraînerait une erreur en raison des différents types.
Cela est possible car Gradle génère automatiquement une méthode de définition pour les propriétés de type «Propriété».
build.gradle
apply plugin: sample.FooPlugin
foo {
inputFile = "fromDir/aaa.txt"
outputDir = "build"
println delegate.class.methods.find { it.name == "setInputFile" }
}
Méthode de définition automatique des propriétés
> gradle copyFile
...
public void sample.FooPluginExtension_Decorated.setInputFile(java.lang.Object)
...
Cet opérateur d'affectation est le sucre de syntaxe pour l'appel de méthode setInpputFile (Object)
généré automatiquement.
Ce type Propriété
est également disponible pour les propriétés de tâches personnalisées et prend en charge la génération automatique de setter.
CustomCopyTask.groovy
package sample
import org.gradle.api.provider.Property
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputDirectory
class CustomCopyTask extends DefaultTask {
@InputFile
Property<Object> inputFile = project.objects.property(Object)
@OutputDirectory
Property<Object> outputDir = project.objects.property(Object)
@TaskAction
def copy() {
project.copy {
from this.inputFile
into this.outputDir
}
}
}
build.gradle
task foo(type: sample.CustomCopyTask) {
inputFile = "fromDir/aaa.txt"
outputDir = "build"
}
Si vous souhaitez déclarer une propriété dans une collection, vous pouvez utiliser ListProperty (https://docs.gradle.org/current/javadoc/org/gradle/api/provider/ListProperty.html) ou SetProperty (https: // docs. Il existe des sous-types tels que gradle.org/current/javadoc/org/gradle/api/provider/SetProperty.html). Les deux ont une méthode de fabrique dans ʻObjectFactory`, vous pouvez donc créer un objet à partir de celle-ci.
Gradle a une ** tâche de cycle de vie **.
Les tâches du cycle de vie ne se traitent pas toutes seules. Au lieu de cela, il joue un rôle en exprimant un concept et en s'appuyant sur d'autres tâches.
Par exemple, dans Base Plugin, [check](https://docs.gradle.org/current/userguide/base_plugin.html# Une tâche appelée sec: base_tasks) est définie.
Cette tâche check
elle-même ne fait rien, mais exprime le concept de" l'exécution du traitement de vérification de projet ".
Lorsqu'un plug-in ajoute une tâche pour effectuer le traitement de vérification, ajoutez la tâche de vérification à la dépendance de check
.
Si tous les plugins sont implémentés de cette façon, tout ce que vous avez à faire est d'exécuter check
et tous les processus de validation fonctionneront.
Par exemple, le plugin Java (https://docs.gradle.org/current/userguide/java_plugin.html#lifecycle_tasks) ajoute la tâche test
à la dépendance check
.
Cela signifie que si vous exécutez check
, vous exécuterez également test
.