Как определять и вызывать собственные методы в build.gradle

79

В рамках моего проекта мне нужно читать файлы из каталога и выполнять некоторые операции в скрипте сборки. Для каждого файла операция одинакова (чтение некоторых запросов sql и их выполнение). Я думаю, что это повторяющаяся задача, и лучше писать внутри метода. Поскольку я новичок в Gradle, я не знаю, как это должно быть. Пожалуйста помоги.

Томин
источник

Ответы:

109

Один из подходов приведен ниже:

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

Обратите внимание, что это создается для объема проекта, т.е. глобально доступный для проекта, который может быть вызван следующим образом в любом месте сценария сборки, используя myMethod(p1, p2)что эквивалентноproject.myMethod(p1, p2)

Метод также может быть определен в различных областях, например в задачах:

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

    doLast {
        myMethod(p1, p2) // This will resolve 'myMethod' defined in task
    }
}
Невидимая стрела
источник
Еще одно сомнение. Могу ли я отметить метод, локальный для задачи ?. ext.myMethod пометит его как глобальный.
Tomin
3
Когда мы используем ext, область действия ограничена тем, где она определена, т.е. если он определен для задачи, он является локальным для задачи. Он работает через сущности (такие как проект, задача и т. Д.), Реализующие ExtensionAware . Это добавляет ExtraPropertiesExtension, который настраивается с помощью extдирективы.
Invisible Arrow
Это означает, что я могу использовать одно и то же имя метода в разных задачах без каких-либо конфликтов. т.е. ext.myMethod в двух или более задачах должен работать.
Tomin
1
При доступе из подпроекта можно получить доступ как rootProject.ext.myMethod (p1, p2)
Philippe
30

Если вы определили какие-либо методы в любом другом файле * .gradle - ext.method () сделает его доступным для всего проекта. Например, вот

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

Без формата ext.method () метод будет доступен только в объявленном им файле * .gradle. То же самое и со свойствами.

Роуленд Мтетези
источник
27

Вы можете определить методы следующим образом:

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

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

Вы можете найти более подробную информацию в документации gradle Глава 62. Организация Build Logic

Иван Маринов
источник
1
Я пробовал это, однако метод, который я создаю, выполняется для каждой выполняемой мной задачи, например, при попытке запустить ./gradlew clean - я вижу, что метод выполняется, и это не то, что я хочу - знаете ли вы, что может быть проблемой?
user1002065
@ user1002065 трудно сказать, не видя вашей настройки, не могли бы вы поделиться (т.е. вкратце), тогда я мог бы попытаться помочь
Иван Маринов
11

Пример с корневым объектом, содержащим методы.

файл 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'
        }
    },

]

build.gradle файл

apply from: 'hg.gradle'

hg.clone('path/to/repo')
Кевин Струиллоу
источник
3

Почему-то, может быть, потому, что прошло пять лет после ОП, но ни один из

ext.someMethod = { foo ->
   methodBody
}

подходы у меня работают. Вместо этого простое определение функции, похоже, выполняет свою работу в моем файле 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)
    }       
}

И я называю это в другом месте своего скрипта без префикса, т.е. retrieveEnvvar("APP_PASSWORD")

Сейчас 2020 год, поэтому я использую Gradle 6.1.1.

ether_joe
источник
Я также использую gradle 6.1.1, ex.someMethod = {} отлично работает. Просто я не мог использовать имена параметров при вызове лямбды.
rpattabi 02
0

@ether_joe, ответ, получивший наибольшее количество голосов от @InvisibleArrow выше, действительно работает, однако вы должны определить метод, который вы вызываете, перед его вызовом, то есть ранее в build.gradleфайле.

Вы можете увидеть пример здесь . Я использовал этот подход с Gradle 6.5, и он работает.

Марракуен
источник