Cómo definir y llamar a métodos personalizados en build.gradle

79

Como parte de mi proyecto, necesito leer archivos de un directorio y realizar algunas operaciones, todas ellas en el script de compilación. Para cada archivo, la operación es la misma (leer algunas consultas SQL y ejecutarlas). Creo que es una tarea repetitiva y es mejor escribir dentro de un método. Como soy nuevo en Gradle, no sé cómo debería ser. Por favor ayuda.

Tomin
fuente

Respuestas:

109

Un enfoque dado a continuación:

ext.myMethod = { param1, param2 ->
    // Method body here
}

Tenga en cuenta que esto se crea para el alcance del proyecto, es decir. disponible globalmente para el proyecto, que se puede invocar de la siguiente manera en cualquier parte del script de compilación usando myMethod(p1, p2)que es equivalente aproject.myMethod(p1, p2)

El método también se puede definir en diferentes ámbitos, como dentro de las tareas:

task myTask {
    ext.myMethod = { param1, param2 ->
        // Method body here
    }

    doLast {
        myMethod(p1, p2) // This will resolve 'myMethod' defined in task
    }
}
Flecha invisible
fuente
Una duda más. ¿Puedo marcar un método local a la tarea ?. ext.myMethod lo marcará como global.
Tomin
3
Cuando usamos ext, el alcance está restringido a donde está definido, es decir. si se define en una tarea, es local para la tarea. La forma en que funciona es a través de entidades (como proyecto, tarea, etc.) que implementan ExtensionAware . Esto agrega una ExtraPropertiesExtension que se configura a través de la extdirectiva.
Flecha invisible
Eso significa que puedo usar el mismo nombre de método en diferentes tareas sin ningún conflicto. es decir; ext.myMethod en dos o más tareas debería funcionar.
Tomin
1
Al acceder desde un subproyecto, se puede acceder como rootProject.ext.myMethod (p1, p2)
Philippe
30

Si ha definido algún método en cualquier otro archivo * .gradle - ext.method () lo hace accesible en todo el proyecto. Por ejemplo, aquí hay un

versioning.gradle

// ext makes method callable project wide
ext.getVersionName = { ->
    try {
        def branchout = new ByteArrayOutputStream()
        exec {
            commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
            standardOutput = branchout
        }
        def branch = branchout.toString().trim()

        if (branch.equals("master")) {
            def stdout = new ByteArrayOutputStream()
            exec {
                commandLine 'git', 'describe', '--tags'
                standardOutput = stdout
            }
            return stdout.toString().trim()
        } else {
            return branch;
        }
    }
    catch (ignored) {
        return null;
    }
}

build.gradle

task showVersion << {
    // Use inherited method
    println 'VersionName: ' + getVersionName()
}

Sin el formato ext.method (), el método solo estará disponible dentro del archivo * .gradle que está declarado. Lo mismo ocurre con las propiedades.

Rowland Mtetezi
fuente
27

Puede definir métodos de la siguiente manera:

// Define an extra property
ext.srcDirName = 'src/java'

// Define a method
def getSrcDir(project) {
    return project.file(srcDirName)
}

Puede encontrar más detalles en el Capítulo 62 de la documentación de gradle . Organización de la lógica de compilación

Ivan Marinov
fuente
1
Intenté esto, sin embargo, el método que estoy creando se ejecuta en cada tarea que estoy ejecutando, por ejemplo, cuando intento ejecutar ./gradlew clean: veo que el método se está ejecutando y esto no es lo que quiero, ¿sabes qué podría ser el problema?
user1002065
@ user1002065 es difícil de decir sin ver su configuración, si pudiera compartir (es decir, como una esencia), entonces podría intentar ayudar
Ivan Marinov
11

Un ejemplo con un objeto raíz que contiene métodos.

Archivo hg.gradle:

ext.hg = [

    cloneOrPull: { source, dest, branch ->
        if (!dest.isDirectory())
            hg.clone(source, dest, branch)
        else
            hg.pull(dest)
        hg.update(dest, branch)
    },

    clone: { source, dest, branch ->
        dest.mkdirs()
        exec {
            commandLine 'hg', 'clone', '--noupdate', source, dest.absolutePath
        }
    },

    pull: { dest ->
        exec {
            workingDir dest.absolutePath
            commandLine 'hg', 'pull'
        }
    },

]

archivo build.gradle

apply from: 'hg.gradle'

hg.clone('path/to/repo')
Kevin Struillou
fuente
3

De alguna manera, tal vez porque han pasado cinco años desde el OP, pero ninguno de los

ext.someMethod = { foo ->
   methodBody
}

enfoques están funcionando para mí. En cambio, una definición de función simple parece estar haciendo el trabajo en mi archivo gradle:

def retrieveEnvvar(String envvar_name) {
    if ( System.getenv(envvar_name) == "" ) {
        throw new InvalidUserDataException("\n\n\nPlease specify environment variable ${envvar_name}\n")
    } else {
        return System.getenv(envvar_name)
    }       
}

Y lo llamo en otra parte de mi script sin prefijo, es decir retrieveEnvvar("APP_PASSWORD")

Esto es 2020, así que estoy usando Gradle 6.1.1.

ether_joe
fuente
También estoy en gradle 6.1.1, ex.someMethod = {} funciona bien. Solo que no pude usar nombres de parámetros al llamar a lambda.
rpattabi
0

@ether_joe la respuesta de arriba votado por @InvisibleArrow anterior hace el trabajo sin embargo se debe definir el método que llama antes de que usted le llama - es decir, a principios de build.gradlearchivo.

Puedes ver un ejemplo aquí . He usado este enfoque con Gradle 6.5 y funciona.

marracuene
fuente