Jak definiować i wywoływać metody niestandardowe w pliku build.gradle

79

W ramach mojego projektu muszę odczytać pliki z katalogu i wykonać kilka operacji w skrypcie kompilacji. Dla każdego pliku operacja jest taka sama (odczytywanie niektórych zapytań sql i wykonywanie ich). Myślę, że to powtarzalne zadanie i lepiej jest pisać wewnątrz metody. Ponieważ jestem nowy w gradle, nie wiem, jak powinno być. Proszę pomóż.

Tomina
źródło

Odpowiedzi:

109

Jedno podejście podane poniżej:

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

Zauważ, że zostanie to utworzone dla zakresu projektu, tj. globalnie dostępne dla projektu, które można wywołać w następujący sposób w dowolnym miejscu skryptu kompilacji, przy użyciu myMethod(p1, p2)którego jest odpowiednikiemproject.myMethod(p1, p2)

Metodę można również zdefiniować w różnych zakresach, na przykład w zadaniach:

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

    doLast {
        myMethod(p1, p2) // This will resolve 'myMethod' defined in task
    }
}
Niewidzialna strzała
źródło
Jeszcze jedna wątpliwość. Czy mogę oznaczyć metodę jako lokalną dla zadania? ext.myMethod oznaczy go jako globalny.
Tomin
3
Kiedy używamy ext, zakres jest ograniczony do miejsca, w którym jest zdefiniowany, tj. jeśli jest zdefiniowana w zadaniu, jest lokalna dla zadania. Działa to za pośrednictwem jednostek (takich jak projekt, zadanie itp.), Które implementują ExtensionAware . Dodaje to ExtraPropertiesExtension, który jest konfigurowany za pomocą extdyrektywy.
Invisible Arrow
Oznacza to, że mogę używać tej samej nazwy metody w różnych zadaniach bez żadnych konfliktów. to znaczy; ext.myMethod w dwóch lub więcej zadaniach powinno działać.
Tomin
1
Podczas uzyskiwania dostępu z podprojektu można uzyskać dostęp jako rootProject.ext.myMethod (p1, p2)
Philippe
30

Jeśli zdefiniowałeś jakieś metody w jakimkolwiek innym pliku * .gradle - ext.method () udostępnia je w całym projekcie. Na przykład tutaj jest

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

Bez formatu ext.method () metoda będzie dostępna tylko w zadeklarowanym pliku * .gradle. To samo dotyczy właściwości.

Rowland Mtetezi
źródło
27

Możesz zdefiniować metody w następujący sposób:

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

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

Więcej szczegółów można znaleźć w dokumentacji gradle Rozdział 62. Organizowanie logiki kompilacji

Ivan Marinov
źródło
1
Próbowałem tego, ale metoda, którą tworzę, jest wykonywana przy każdym zadaniu, które uruchamiam, na przykład podczas próby uruchomienia ./gradlew czysty - widzę, że metoda jest wykonywana i nie tego chcę - czy wiesz, co może być problemem?
user1002065
@ user1002065 trudno powiedzieć bez zapoznania się z twoją konfiguracją, gdybyś mógł podzielić się (tj. w skrócie), to mógłbym spróbować pomóc
Ivan Marinov
11

Przykład z obiektem root zawierającym metody.

hg.gradle plik:

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'
        }
    },

]

build.gradle

apply from: 'hg.gradle'

hg.clone('path/to/repo')
Kevin Struillou
źródło
3

W jakiś sposób może dlatego, że minęło pięć lat od OP, ale żaden z

ext.someMethod = { foo ->
   methodBody
}

podejścia działają dla mnie. Zamiast tego wydaje się, że prosta definicja funkcji wykonuje zadanie w moim pliku 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)
    }       
}

I nazywam to w innym miejscu mojego skryptu bez przedrostka, tj retrieveEnvvar("APP_PASSWORD")

Jest rok 2020, więc używam Gradle 6.1.1.

ether_joe
źródło
Jestem też na gradle 6.1.1, ex.someMethod = {} działa dobrze. Po prostu nie mogłem używać nazw parametrów podczas wywoływania lambdy.
rpattabi
0

@ether_joe - najczęściej głosowana odpowiedź przez @InvisibleArrow powyżej czyni pracę jednak należy zdefiniować metodę zadzwonić zanim to nazwać - czyli wcześniej w build.gradlepliku.

Możesz zobaczyć przykład tutaj . Użyłem tego podejścia w Gradle 6.5 i działa.

marrakuen
źródło