Плагин sbt динамически загружать определенный пользователем код?
Я работаю над плагином sbt, который генерирует модели Scala на основе базы данных с помощью генератора кода Slick
Я бы, конечно, хотел, чтобы пользователи переопределяли генератор кода, поэтому мой плагин должен поддерживать это:
В любом случае, я могу динамически загружать класс Scala с указанием пути к нему в ключах плагина build.sbt? Например, в родительском build.sbt пользователя она предоставит что-то вроде
codegen.override=com.company.project.CustomCodegenerator
который выглядит такСвязанные с выше; пользовательский codegen может использовать некоторые другие библиотеки, поэтому простой динамической загрузки классов может быть недостаточно. В любом случае плагин sbt может наследовать зависимости проекта, используя этот плагин?
Вот полное обсуждение этого: https://github.com/papauschek/play-slick-evolutions-plugin/issues/1
1 ответ
В конце дня вам нужно запустить некоторый код для генерации исходных файлов Scala.
Генерация файлов
Как вы знаете, sbt имеет хук для генерации исходных файлов, который называется sourceGenerators
, который задокументирован в Генерация файлов. Вы как автор плагина должны предоставить задачу, которая генерирует Seq[File]
под (sourceManaged in Compile).value / "garfield"
используя генератор кода Slick в качестве реализации по умолчанию. Давайте назовем это generateModel
, Ваш плагин может иметь следующие настройки:
sourceGenerators in Compile += generateModel.taskValue,
generateModel := defaultGenerateModel.value,
defaultGenerateModel := { ... }
Если ваш пользователь сборки хочет перемонтировать generateModel
Он или она могли бы сделать это так:
generateModel := {
val file = (sourceManaged in Compile).value / "garfield" / "Foo.scala"
IO.write(file, """case class Foo() {}""")
Seq(file)
}
Если генерация кода содержится в плагине sbt, как описано выше, вам не нужно делать какие-либо динамические вещи. поскольку play-slick-evolutions-codegen-plugin
зависит от slick-codegen, это не должно быть проблемой.
Динамическая загрузка кода пользователя
Поскольку вопрос заключается непосредственно в динамической загрузке кода пользователя, я бы также добавил несколько указателей на это.
- Одним из способов является использование
sbt.Run
API из существующей конфигурации. Это эквивалентно звонкуrun
Задача с некоторым настроенным параметром. Если вы генерируете код дляCompile
конфигурация, использование бегуна для любой конфигурации, которая зависит от него, не будет хорошей идеей. - Другой подобный способ заключается в использовании
sbt.Fork
API. Форкинг позволяет запускать код вне плагина.
Учитывая, что sbt будет автоматически упорядочивать задачи на основе их зависимостей и выполнять несколько задач параллельно, динамическое выполнение кода чревато неожиданными опасностями.