27 de febrero de 2019 [Gradle, Groovy, Java]
En este mundo loco, Gradle a veces parece la opción más sensata para crear proyectos Java o Kotlin.
Pero, ¿qué significa realmente todo lo que hay dentro de build.gradle?
¿Y cuándo se ejecuta mi código?
¿Y cómo crear tareas?
¿Y cómo se convence a una tarea de que dependa de otra tarea?
[Related: Clever things people do in Groovy so you have to know about them]
Preparar
Para usar Gradle, mantenga presionada cualquier versión el tiempo suficiente para crear un archivo gradlew local y luego use esa versión.
$ mkdir gradle-experiments $ cd gradle-experiments $ sudo apt install gradle # Briefly install the system version of gradle ... $ gradle wrapper --gradle-version=5.2.1 $ sudo apt remove gradle # Optional - uninstalls the system version $ ./gradlew tasks ... If all is good, this should ... ... print a list of available tasks. ...
Es normal que gradlew y todo el directorio gradle/ que crea se registren en el control de fuente. Esto significa que todos los que extraigan código del control de fuente tendrán una versión predecible de Gradle.
¿Qué es build.gradle?
build.gradle es un programa Groovy que Gradle ejecuta en un contexto preparado para usted. Ese contexto significa que en realidad estás llamando a un método del objeto Proyecto y modificando sus propiedades. El hecho de que Groovy te permita perder mucha puntuación hace que sea más difícil de ver, pero es cierto.
Lo primero que debes notar es que Gradle ejecuta tu código directamente, por lo que si tu build.gradle se ve así (y solo esto):
println("Hello")
cuando ejecutas Gradle tu código se ejecuta:
$ ./gradlew -q Hello ... more guff ...
De modo que ese código se ejecuta incluso si no le pides a Gradle que ejecute la tarea que contiene ese código. Se ejecuta en el “momento de configuración”, es decir, cuando Gradle comprende su archivo build.gradle. En realidad, eso es lo que significa “comprender”. ejecutar él.
¿Recuerdas cuando dije que este código se ejecuta en el contexto del Proyecto? Lo que esto significa es que si tienes algo como esto en tu build.gradle:
repositories {
jcenter()
}
el verdadero significado es así:
project.repositories(
{
it.jcenter()
}
)
Llamas al método del repositorio en el objeto del proyecto. El argumento del método del repositorio es un cierre de Groovy, que es una masa de código que se ejecutará más adelante. He usado el nombre mágico anterior para indicar que jcenter es simplemente un método llamado en el objeto que es el contexto de cierre cuando se ejecuta.
¿Cuándo se ejecuta? Averigüemos:
println("before")
project.repositories( {
println("within")
jcenter()
})
println("after")
$ ./gradlew -q before within after ... more guff ...
Esto me sorprendió: esto significa que el cierre que pasa al repositorio en realidad se ejecuta inmediatamente, como parte de la ejecución del repositorio, antes de que la ejecución llegue a la línea después de esa llamada.
Como veremos más adelante, algunos de los cierres que crea no funcionan así de inmediato.
Una vez que sepa que build.gradle en realidad modifica los objetos del proyecto, tendrá un punto de partida para comprender la documentación de referencia de Gradle.
¿Cómo crear tareas?
Probablemente no deberías hacer esto con demasiada frecuencia, pero fue una lección para mí sobre cómo crear mis propias tareas personalizadas. He aquí un ejemplo:
tasks.register("mytask") {
doLast {
println("running mytask")
}
}
Crea una nueva tarea llamando al método de registro en la propiedad de tarea del objeto Proyecto. El registro toma dos argumentos: un nombre para la tarea (“mytask” aquí) y un cierre con algo de código dentro para ejecutar cuando decidamos que necesitamos esta tarea. El cierre se llevó a cabo en ese contexto. No poder ve el objeto Proyecto, pero en su lugar puede ver el objeto Tarea que creó. El objeto Task tiene un método doLast al que llamamos, pasándole un cierre que se ejecutará cuando la tarea realmente se ejecute (No directo).
Si eliminamos parte del azúcar sintáctico, el build.gradle anterior se vería así:
tasks.register(
"mytask",
{
it.doLast(
{
println("running mytask")
}
)
}
)
Arriba podemos ver que el registro en realidad toma dos argumentos como dije anteriormente: la primera versión usa una característica Groovy donde si pasa el último argumento y escribe un cierre inmediatamente después, el cierre se pasa como último argumento. Confuso, ¿eh?
Nuevamente, tenga en cuenta que doLast es un método en el objeto Task que está implícitamente disponible cuando se ejecuta el cierre.
Entonces hemos creado una tarea que podemos ejecutar:
./gradlew -q mytask running mytask
¿Cómo se hace que una tarea dependa de otra tarea?
Si quiero formatear el código antes de compilarlo (por ejemplo), a veces necesito modificar una tarea para que dependa de otra tarea. Esto se puede hacer para tareas que usted cree o tareas preexistentes. He aquí un ejemplo:
plugins {
id "java"
}
tasks.register("mytask") {
doLast {
println("running mytask")
}
}
compileJava {
dependsOn tasks.named("mytask")
}
Entonces, llamar al método de complementos en el Proyecto en la parte superior con un cierre que ejecuta el método id en algo modifica el Proyecto para que tenga un nuevo método llamado compileJava que llamamos en la parte inferior, pasando el cierre para ejecutar. El cierre se ejecuta en el contexto de un objeto Tarea (similar a cuando creamos una tarea, pero ahora nos permite modificar tareas preexistentes). Llamamos al método dependOn en el objeto Task, pasando otro objeto Task que hemos obtenido llamando al método nombrado en el objeto Task.
[Side note: the register method actually returns a Task object that we could have passed to dependsOn without looking it up again using named, but Groovy doesn’t provide a very convenient way of holding on to that reference, so we didn’t do it. The Kotlin example below shows that this is quite simple in Kotlin.]
¿Cómo hacer todo esto en Kotlin?
Debido a que un DSL que oculta lo que realmente está sucediendo no es suficiente para usted, Gradle ahora proporciona un segundo DSL que oculta lo que está sucediendo de una manera ligeramente diferente, es decir, un programa escrito en Kotlin en lugar de Groovy. Esto es un poco mejor, porque Kotlin no te permite hacer tantos trucos estúpidos como Groovy.
A continuación se muestran todos nuestros ejemplos en Kotlin. Comienza exactamente de la misma manera, siguiendo “Configuración” arriba. Recuerde nombrar su archivo de compilación build.gradle.kts.
Saluda a Gradle Kotlin
println("Hello")
Esto es idéntico a la versión Groovy.
Utilice el repositorio jcenter en Gradle Kotlin
repositories {
jcenter()
}
Esto es idéntico a la versión Groovy y tiene el mismo significado: un repositorio es un método en un objeto Proyecto que está disponible implícitamente.
La versión “sin azúcar” se ve así en Kotlin:
this.repositories(
{
this.jcenter()
}
)
[Note that the word this is used to access the implicit context. The word it has a different meaning in Kotlin from in Groovy. In Groovy it means the implicit context, but in Kotlin it means the first argument. We didn’t pass any arguments to jcenter when we called it, so we can’t use it, but we were being run in a context, which we can refer to using this. Simple. huh?]
Comando de ejecución en Gradle Kotlin
Hacemos esto build.gradle.kts:
println("before")
project.repositories( {
println("within")
jcenter()
})
println("after")
Vemos este comportamiento:
$ ./gradlew -q before within after
todos los cuales son idénticos a la versión Groovy.
Crear una nueva tarea en Gradle Kotlin
tasks.register("mytask") {
doLast {
println("running mytask")
}
}
Tenga en cuenta que Kotlin le permite hacer el mismo truco que Groovy: pasar argumentos adicionales a funciones que son cierres escribiéndolos tan pronto como termine de llamarlas. Esto es fantástico para las personas a las que no les gusta que sus llaves de cierre duren más de lo esperado. Como alguien que ama Lisp, estoy totalmente a favor de cerrar corchetes, pero ¿qué sé yo?
Lo anterior es idéntico a la versión Groovy, pero ligeramente diferente si no está endulzado:
tasks.register(
"mytask",
{
this.doLast(
{
println("running mytask")
}
)
}
)
Una tarea depende de otra tarea en Gradle Kotlin
plugins {
java
}
val mytask = tasks.register("mytask") {
doLast {
println("running mytask")
}
}
tasks.compileJava {
dependsOn(mytask)
}
Esto es ligeramente diferente de la versión Groovy, aunque el significado es el mismo: comenzamos en el contexto de un objeto Proyecto al que llamamos método.
El código para hacer que una tarea dependa de otra tarea contendrá un objeto Tarea llamado compileJava desde dentro de las propiedades de la tarea del Proyecto y lo llamará (porque es un objeto invocable). Pasamos un cierre que se ejecuta en el contexto de este objeto Task, llamamos a su método dependOn y pasamos una referencia al objeto mytask, que es una Task y se creó en el código anterior.
Se aceptan correcciones y aclaraciones.
Lo anterior es lo que resolví experimentando e intentando leer la documentación de Gradle. Agregue comentarios que aclaren la confusión y corrijan errores.
PakarPBN
A Private Blog Network (PBN) is a collection of websites that are controlled by a single individual or organization and used primarily to build backlinks to a “money site” in order to influence its ranking in search engines such as Google. The core idea behind a PBN is based on the importance of backlinks in Google’s ranking algorithm. Since Google views backlinks as signals of authority and trust, some website owners attempt to artificially create these signals through a controlled network of sites.
In a typical PBN setup, the owner acquires expired or aged domains that already have existing authority, backlinks, and history. These domains are rebuilt with new content and hosted separately, often using different IP addresses, hosting providers, themes, and ownership details to make them appear unrelated. Within the content published on these sites, links are strategically placed that point to the main website the owner wants to rank higher. By doing this, the owner attempts to pass link equity (also known as “link juice”) from the PBN sites to the target website.
The purpose of a PBN is to give the impression that the target website is naturally earning links from multiple independent sources. If done effectively, this can temporarily improve keyword rankings, increase organic visibility, and drive more traffic from search results.