Я хочу реализовать плагин с дополнительными зависимостями, предоставляемыми пользователем, например, как некоторые плагины Gradle, которые позволяют:
dependencies {
// ...
dokkaPlugin(libs.dokka.versioning.plugin)
}
Мне удалось создать configuration
в проекте с именем myPlugin
:
val config = project.configurations.create("myPlugin")
Итак, теперь в клиентских проектах, использующих мой плагин, я могу делать:
dependencies {
myPlugin("com.example:example:1.0.0")
}
Вопрос в том, как применить мою конфигурацию для запуска некоторого Java-кода с путем к классам, содержащим myPlugin
зависимости?
Вот еще код для контекста:
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
val extension = project.extensions.create<MyPluginExtension>("myPlugin")
val config = project.configurations.create("myPlugin")
val task = project.tasks.register<MyTask>("myTask") {
// ...
}
}
}
class MyTask : DefaultTask() {
@TaskAction
fun execute() {
val config = project.configurations.getByName("myPlugin")
// How to run some java code using this config?
}
}
Я понимаю, что во время компиляции моего плагина эти клиентские зависимости не будут доступны, поэтому я не смогу использовать классы из com.example:example
напрямую. Но я все еще хочу создать несколько экземпляров с помощью отражения или получить их с помощью ServiceLoader
API.
Configuration
расширяет FileCollection
, то есть является оберткой группы файлов. Вы можете разрешить эту конфигурацию, когда будете готовы, и добавить ее в путь к классам.
В Gradle есть встроенная задача JavaExec, которую вы можете использовать для создания собственных задач, выполняющих программы Java.
Таким образом, вы можете зарегистрировать новую задачу и настроить ее со всеми теми же элементами, которые вы бы добавили, как если бы вы запускали команду java
из командной строки:
tasks.register<JavaExec>("myRunTask") {
args("something the program needs to know")
classpath(
theJarsWithTheCompiledCodeOfMyProgram, // Build this in a separate project
myNewConfiguration // Defined in the plugin for user's use
)
mainClass.set("the.main.clazz")
}
Чтобы получить theJarsWithTheCompiledCodeOfMyProgram
, вы можете создать дополнительный подпроект MyPluginApp
к вашему плагину в мультипроектном проекте; и укажите MyPluginApp
JAR как зависимость проекта, в котором применяется плагин, используя координаты MyPluginApp
Maven, гарантируя, что целевой проект имеет доступ к репозиторию с этим JAR в нем (или он находится в той же сборке Gradle).
Если все это кажется слишком сложным, альтернативно вы можете запустить все в плагине, разрешив новую конфигурацию и используя полученные файлы для создания нового экземпляра URLClassLoader и загрузив из них все, что вам нужно.
Такой код будет запускаться из метода @TaskAction
задачи, который вы определяете.
Я бы не рекомендовал таким образом разрешать путь к классам buildscript. В ответе я объяснил вам еще несколько вариантов.
Боюсь, я до сих пор не понял предложенный вами подход. Если я добавлю конфигурацию в скрипт сборки плагина (configurations { create("myPluginApp") {} }
), она не будет доступна внутри кода плагина. И если я разрешаю его «в файл» в своем сценарии сборки, то плагин нельзя будет использовать за пределами родительского проекта.
Итак, мне удалось сделать следующее: - создать конфигурацию myPluginApp
в коде плагина (не построить скрипт) - программно добавить зависимость myPluginApp
к project
- теперь у меня есть две конфигурации, которые я могу использовать для запуска своего приложения из плагина. Однако необходимо сделать один трюк, чтобы выполнить версию my-plugin-app, соответствующую версии my-pluign. Для этого я использовал предложенный вами подход: сохраните версию плагина в файле ресурсов во время сборки и используйте эту версию на шаге 2, чтобы указать версию приложения. Что вы думаете?
Я согласен, что первоначально предложенный подход не подходил для опубликованного плагина. Я внес поправки, чтобы показать подход к вводу координат Maven (думаю, вы тоже об этом говорите). Я думаю, что это «правильный» способ сделать это :)
Как создать
theJarsWithTheCompiledCodeOfMyProgram
, когда программа создается как родственный подпроект? Мне удалось сделать это следующим образом:classpath(project.buildscript.configurations.getByName("classpath"), config)
учитывая, что плагин находится в пути к классу сценария сборки. Интересно, есть ли способ сузитьproject.buildscript.configurations.getByName("classpath"),
путь к классам самого плагина?